/* ============================================================
   Saaed Vegetable Trading — stylesheet
   Design tokens copied from the Saaed design system (colors,
   type, spacing, radius, shadow). Edit values in :root only.
   ============================================================ */
/* The fonts were an @import from fonts.googleapis.com here. They are now
   self-hosted and loaded by assets/css/fonts.css, linked from the <head> before
   this file — same three typefaces, same weights, one origin, and no @import
   chain to block the first paint. See assets/css/fonts.css for the detail. */

:root{
  --green-brand:#14603F;--green-accent:#17794E;--green-deep:#10352B;--green-uplift:#2C5449;
  --green-light:#D8EADF;--amber-harvest:#C4923E;--amber-light:#E0C79E;--amber-lightest:#FBF6EC;--slate-dark:oklch(24% 0.014 155);
  --canvas-warm:#F4F1EA;--ceramic:#EBE8E2;--card-white:#FFFFFF;--neutral-cool:#F8F8F7;
  --text-primary:rgba(0,0,0,.87);--text-secondary:rgba(0,0,0,.58);
  --text-on-dark:#FFFFFF;--text-on-dark-muted:rgba(255,255,255,.70);
  --sale-red:#C42014;--warning-amber:#E08A00;--success-green:#17794E;--out-of-stock-gray:#A7A7A7;
  --input-border:#D6DBDE;
  --font-sans:Inter,"Helvetica Neue",Helvetica,Arial,sans-serif;
  --font-serif:Lora,"Iowan Old Style",Georgia,serif;
  --font-script:Kalam,"Comic Sans MS",cursive;
  --track-tight:-0.01em;
  --text-display:5.0rem;--text-jumbo:3.6rem;--text-hero-lg:2.8rem;--text-h1:2.4rem;--text-h2:2.4rem;
  --text-body-lg:1.9rem;--text-body:1.6rem;--text-small:1.4rem;--text-micro:1.3rem;
  --text-price-lg:2.0rem;--text-price-struck:1.4rem;--text-caption-upper:1.3rem;
  --space-1:.4rem;--space-2:.8rem;--space-3:1.6rem;--space-4:2.4rem;--space-5:3.2rem;--space-6:4.0rem;--space-7:4.8rem;--space-8:5.6rem;--space-9:6.4rem;
  --gutter-mobile:1.6rem;--gutter-tablet:2.4rem;--gutter-desktop:4.0rem;--content-max:1440px;
  /* Chrome, not content. The primary nav is a band of 12 short links; held to
     --content-max it stranded ~240px of empty white either side on a 1920
     screen while the links bunched in the middle. It gets its own wider bound
     so it can reach toward the edges without moving the grid, hero or footer,
     which all stay on --content-max. --text-nav started a step under
     --text-micro; the labels were tidy at that size and hard to read at arm's
     length, so it sits on --text-small now. It keeps its own token because this
     band is the only place the decision is made. */
  --nav-max:1680px;--text-nav:1.4rem;
  --radius-pill:50px;--radius-card:12px;--radius-field:4px;--radius-sheet-top:12px 12px 0 0;
  --shadow-card:0 0 .5px rgba(0,0,0,.14),0 1px 1px rgba(0,0,0,.24);
  --shadow-nav:0 1px 3px rgba(0,0,0,.1),0 2px 2px rgba(0,0,0,.06),0 0 2px rgba(0,0,0,.07);
  --shadow-fab-base:0 0 6px rgba(0,0,0,.24);--shadow-fab-ambient:0 8px 12px rgba(0,0,0,.14);
  --shadow-sheet:0 -2px 12px rgba(0,0,0,.12);
  --press-scale:scale(.95);
}
html{font-size:62.5%}
*{box-sizing:border-box}
body{margin:0;background:var(--canvas-warm);color:var(--text-primary);font-family:var(--font-sans);letter-spacing:var(--track-tight);font-size:1.6rem;line-height:1.5}
img{max-width:100%;display:block}
/* hidden means hidden. The attribute only carries display:none from the user
   agent stylesheet, so any author rule that sets display beats it — and one
   did: .choice-row is display:flex, so every day's delivery slots stayed on
   screen at checkout. Thirty-five time chips, the same five windows repeated
   seven times with nothing to say which day each belonged to, on the page where
   the order is placed.
   !important is right here rather than lazy: there is no case where an element
   carrying [hidden] should be visible, and without it every future display rule
   is another chance to reintroduce this. */
[hidden]{display:none !important}
a{color:var(--green-accent);text-decoration:none}
a:hover{color:var(--green-brand)}
button{font-family:var(--font-sans);cursor:pointer}
h1,h2,h3,p{margin:0}
.container{max-width:var(--content-max);margin:0 auto;padding:0 var(--gutter-desktop)}
/* Vertical only. This was `padding: var(--space-7) 0`, and the shorthand set
   left and right to zero — on every element carrying both classes, which is the
   <main> of nearly every page in the site. .container's gutter was being wiped
   by the rule immediately after it, so page content sat flush against the edge
   of the screen at any width narrower than --content-max. Most visible on a
   phone, where it read as the page having no margins at all. */
.section{padding-block:var(--space-7)}
button,.pill-btn,a.pill-btn{transition:all .2s ease}
button:active,.pill-btn:active{transform:var(--press-scale)}
:focus-visible{outline:2px solid var(--green-accent);outline-offset:2px}

/* ---- buttons & chips ---- */
.pill-btn{display:inline-flex;align-items:center;justify-content:center;gap:.6rem;border-radius:var(--radius-pill);border:none;font-weight:600;font-size:var(--text-small);padding:0 2.4rem;height:44px;white-space:nowrap}
.pill-btn.primary{background:var(--green-accent);color:var(--text-on-dark)}
.pill-btn.primary:hover{background:var(--green-brand)}
.pill-btn.outline{background:transparent;border:1.5px solid var(--green-accent);color:var(--green-accent)}
.pill-btn.outline:hover{background:var(--green-light)}
.pill-btn.small{height:36px;padding:0 1.6rem;font-size:var(--text-micro)}
.ghost-link{display:inline-flex;align-items:center;gap:.6rem;font-weight:600;color:var(--green-accent);font-size:var(--text-small)}
.chip{border-radius:var(--radius-pill);border:1px solid var(--input-border);background:var(--card-white);padding:.8rem 1.8rem;font-size:var(--text-small);font-weight:600;color:var(--text-primary)}
.chip.active{background:var(--green-accent);border-color:var(--green-accent);color:var(--text-on-dark)}
.badge-count{position:absolute;top:-6px;right:-6px;background:var(--sale-red);color:#fff;font-size:1.1rem;font-weight:700;min-width:18px;height:18px;border-radius:50%;display:flex;align-items:center;justify-content:center;padding:0 3px}

/* ---- announcement + utility bars ---- */
.announcement-bar{background:var(--green-deep);color:var(--text-on-dark);font-size:1.3rem;padding:.9rem 0}
/* The four chrome bands share one width so the logo, the search field and the
   first nav link all start on the same vertical line. Widening the nav alone
   would have pulled it 120px left of the logo above it, which reads as a
   mistake rather than as more room. Page content below stays on --content-max. */
.announcement-bar .container,.utility-bar .container,.site-header .container{max-width:var(--nav-max)}
.announcement-bar .container{display:flex;align-items:center;justify-content:space-between;gap:1.6rem}
.announcement-bar .close-announcement{background:none;border:none;color:var(--text-on-dark-muted);font-size:1.6rem;line-height:1;padding:0}
.announcement-bar.hidden{display:none}
.utility-bar{background:var(--ceramic);font-size:1.3rem;color:var(--text-secondary);padding:.8rem 0}
.utility-bar .container{display:flex;align-items:center;justify-content:space-between;gap:1.6rem}
.utility-bar .u-links{display:flex;gap:1.2rem;align-items:center}
.utility-bar .u-links a{color:var(--text-secondary)}
.utility-bar .u-links span.sep{color:var(--input-border)}
.utility-bar select{border:none;background:transparent;color:var(--text-secondary);font-size:1.3rem}
@media (max-width:992px){.utility-bar{display:none}}
.announcement-side{display:flex;align-items:center;gap:1.6rem;flex-shrink:0}
/* The bar carried the offer and both phone numbers, which ran to three lines and
   77px before a phone had seen anything of the shop. The numbers are in the
   footer and on the contact page; the offer is the part that has to be here.
   The dismiss button stays — hiding the whole block would have taken it too. */
@media (max-width:767px){.announcement-phone{display:none}}

/* ---- header ---- */
.site-header{background:var(--card-white);position:sticky;top:0;z-index:60;padding:1.6rem 0}
.site-header.scrolled{box-shadow:var(--shadow-nav)}
.site-header .container{display:flex;align-items:center;gap:2.4rem}
.logo{display:flex;align-items:center;gap:.8rem;font-weight:700;font-size:2rem;color:var(--green-brand);flex-shrink:0}
.logo svg{flex-shrink:0}
.cat-btn{display:flex;align-items:center;gap:.8rem;background:var(--ceramic);border:none;border-radius:var(--radius-pill);height:44px;padding:0 1.8rem;font-weight:600;font-size:var(--text-small);color:var(--text-primary);flex-shrink:0;position:relative}
.search-wrap{flex:1;position:relative}
.search-bar{display:flex;align-items:center;gap:1rem;background:var(--neutral-cool);border:1px solid var(--input-border);border-radius:var(--radius-pill);height:44px;padding:0 1.8rem}
.search-bar input{border:none;background:none;flex:1;font-size:var(--text-small);outline:none;font-family:var(--font-sans)}
.search-suggestions{position:absolute;top:52px;left:0;right:0;background:var(--card-white);border-radius:var(--radius-card);box-shadow:var(--shadow-nav);display:none;overflow:hidden;z-index:70}
.search-suggestions.open{display:block}
.suggestion-item{display:flex;align-items:center;gap:1.2rem;padding:1rem 1.6rem;border-bottom:1px solid var(--table-hairline,#E7E7E7)}
.suggestion-item:last-child{border-bottom:none}
.suggestion-item img{width:36px;height:36px;object-fit:cover;border-radius:6px;background:var(--ceramic)}
.suggestion-item .s-name{font-size:var(--text-small);font-weight:600}
.suggestion-item .s-price{margin-left:auto;color:var(--sale-red);font-weight:700;font-size:var(--text-small)}
.header-actions{display:flex;align-items:center;gap:2rem;flex-shrink:0}
.header-actions .action{position:relative;display:flex;flex-direction:column;align-items:center;gap:.2rem;background:none;border:none;color:var(--text-primary);font-size:1.1rem;font-weight:600}
.header-actions .action svg{width:22px;height:22px}
.cat-dropdown{position:absolute;top:52px;left:0;background:var(--card-white);border-radius:var(--radius-card);box-shadow:var(--shadow-nav);padding:1.2rem;display:none;min-width:240px;z-index:70}
.cat-dropdown.open{display:grid;grid-template-columns:1fr 1fr}
.cat-dropdown a{padding:.8rem 1rem;border-radius:8px;color:var(--text-primary);font-size:var(--text-small)}
.cat-dropdown a:hover{background:var(--green-light);color:var(--green-brand)}

/* ---- primary nav ---- */
.primary-nav{background:var(--card-white);border-bottom:1px solid var(--input-border);position:relative;z-index:55}
.primary-nav .container{display:flex;align-items:center;justify-content:center;min-height:52px;padding:.6rem var(--gutter-desktop);max-width:var(--nav-max)}
.primary-nav .nav-links{display:flex;flex-wrap:nowrap;justify-content:center;gap:1.6rem;overflow-x:auto;scrollbar-width:none}
/* Once there is genuinely more width than the links need, spread them across it
   rather than leaving the surplus at the two ends. Below this the links can
   still outgrow the bar, so they stay centred and the row scrolls — spreading
   them there would fight the scroll. */
@media (min-width:1200px){
  .primary-nav .nav-links{width:100%;justify-content:space-between;gap:var(--space-3);overflow-x:visible}
}
/* The row used to scroll horizontally at every width it was visible. Setting
   overflow-x to auto makes overflow-y compute to auto too, so the hover panel
   under each link — which is absolutely positioned below the row — was being
   clipped by its own container everywhere. Between the hamburger breakpoint and
   the width where the links fit on one line, wrap to a second row instead of
   scrolling: no overflow box, so the panels are free to hang below. */
@media (min-width:993px) and (max-width:1199px){
  .primary-nav .nav-links{flex-wrap:wrap;overflow:visible;row-gap:.2rem}
}
.primary-nav .nav-links::-webkit-scrollbar{display:none}
.primary-nav .nav-links .nav-item{position:relative;flex-shrink:0}
.primary-nav .nav-links .nav-item>a{white-space:nowrap;font-size:var(--text-nav)}
.primary-nav .nav-links .mini-panel{position:absolute;top:100%;left:50%;transform:translateX(-50%) translateY(4px);background:var(--card-white);border-radius:var(--radius-card);box-shadow:var(--shadow-card),var(--shadow-nav);padding:1rem 1.4rem;min-width:180px;opacity:0;visibility:hidden;transition:opacity .2s ease,transform .2s ease;z-index:60;white-space:nowrap}
.primary-nav .nav-links .nav-item:hover .mini-panel,.primary-nav .nav-links .nav-item:focus-within .mini-panel{opacity:1;visibility:visible;transform:translateX(-50%) translateY(0)}
.primary-nav .nav-links .mini-panel a{display:block;font-size:1.4rem;font-weight:400;color:var(--text-primary);padding:.4rem 0}
.primary-nav .nav-links .mini-panel a:hover{color:var(--green-accent)}
.primary-nav .nav-links a{color:var(--text-primary);font-weight:500;position:relative}
.primary-nav .nav-links a.new::after{content:"New";position:absolute;top:-10px;right:-24px;background:var(--sale-red);color:#fff;font-size:1rem;padding:.1rem .5rem;border-radius:var(--radius-pill)}
.primary-nav .nav-right{display:flex;align-items:center;gap:2rem}
.hamburger-btn{display:none;background:none;border:none;font-size:2rem;line-height:1;color:var(--text-primary);padding:.4rem}
/* Hiding only the links left the band itself standing: 52px of white between
   the header and the hero on every phone, which read as the page being broken.
   The hamburger drawer is the navigation at this size, so the whole band goes. */
@media (max-width:992px){.primary-nav{display:none}.hamburger-btn{display:block}}

/* ---- mega dropdown ---- */
.nav-item{position:relative}
.nav-item>a{display:flex;align-items:center;gap:.4rem}
.mega-panel{position:absolute;top:100%;left:0;background:var(--card-white);border-radius:var(--radius-card);box-shadow:var(--shadow-card),var(--shadow-nav);padding:2.4rem;display:grid;grid-template-columns:repeat(6,150px);gap:2rem;opacity:0;visibility:hidden;transform:translateY(-4px);transition:opacity .2s ease,transform .2s ease,visibility .2s;z-index:56}
.nav-item:hover .mega-panel,.nav-item:focus-within .mega-panel{opacity:1;visibility:visible;transform:translateY(0)}
.mega-col h4{font-size:1.4rem;font-weight:700;text-transform:uppercase;letter-spacing:.325px;color:var(--text-secondary);margin-bottom:1.2rem}
.mega-col a{display:block;font-size:1.5rem;font-weight:400;color:var(--text-primary);padding:.5rem 0}
.mega-col a:hover{color:var(--green-accent)}

/* ---- mobile menu drawer ---- */
.mobile-menu-drawer{position:fixed;top:0;left:0;bottom:0;width:320px;max-width:85vw;background:var(--card-white);z-index:95;transform:translateX(-100%);transition:transform .3s ease;overflow-y:auto}
.mobile-menu-drawer.open{transform:translateX(0)}
.mobile-menu-drawer .mm-head{display:flex;justify-content:space-between;align-items:center;padding:2rem;border-bottom:1px solid var(--input-border)}
.mobile-menu-drawer .mm-body{padding:1rem 2rem 2rem}
.mm-link{display:block;padding:1.4rem 0;font-size:var(--text-body);font-weight:600;color:var(--text-primary);border-bottom:1px solid var(--input-border)}
.mm-accordion-head{width:100%;display:flex;justify-content:space-between;align-items:center;background:none;border:none;padding:1.4rem 0;font-size:var(--text-body);font-weight:600;color:var(--text-primary);border-bottom:1px solid var(--input-border)}
.mm-sub{padding:.4rem 0 1rem 1rem}
.mm-sub a{display:block;font-size:var(--text-small);color:var(--text-primary);padding:.5rem 0}
.mm-sub-group{margin-bottom:1.2rem}
.mm-sub-group h5{font-size:1.2rem;font-weight:700;text-transform:uppercase;color:var(--text-secondary);margin-bottom:.6rem}
.mm-sub-group a{display:block;font-size:var(--text-small);color:var(--text-primary);padding:.4rem 0}

/* ---- hero ---- */
.hero{padding-top:0}
.hero-slider{position:relative;overflow:hidden;height:460px;background:var(--green-deep)}
/* Slides used to swap with display:none/flex, which is a hard cut — the jump
   the brief describes. They all stay laid out now and cross-fade instead, so
   there is nothing to reflow mid-transition. visibility rides along on the same
   timing so a faded-out slide cannot be tabbed into or read by a screen reader.
   The JS is untouched: .active still drives it. */
/* A cross-fade still has a moment where nothing is moving, which reads as the
   pause being reported. The slides travel now: the one leaving goes out to the
   left while the one arriving comes in from the right, both on the same curve,
   so there is always motion between one slide and the next.
   Waiting slides sit off to the right with no transition, so they cannot be
   seen sliding back into position when the loop comes round. */
.hero-slide{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
  transform:translate3d(100%,0,0);opacity:0;visibility:hidden;pointer-events:none;will-change:transform}
.hero-slide.active{transform:translate3d(0,0,0);opacity:1;visibility:visible;pointer-events:auto;
  transition:transform 1s cubic-bezier(.65,0,.35,1),opacity .45s ease}
.hero-slide.is-leaving{transform:translate3d(-100%,0,0);opacity:1;visibility:visible;
  transition:transform 1s cubic-bezier(.65,0,.35,1),opacity .9s ease}
/* The copy arrives just behind the image so the slide resolves instead of
   appearing all at once. Small distance, long ease — the difference between
   premium and busy is usually the distance, not the duration. */
.hero-slide .hero-copy>*{opacity:0;transform:translateY(12px);transition:opacity .7s ease,transform .7s cubic-bezier(.4,0,.2,1)}
.hero-slide.active .hero-copy>*{opacity:1;transform:none}
.hero-slide.active .hero-copy>*:nth-child(2){transition-delay:.08s}
.hero-slide.active .hero-copy>*:nth-child(3){transition-delay:.16s}
.hero-slide.active .hero-copy>*:nth-child(4){transition-delay:.24s}
@media (prefers-reduced-motion:reduce){
  .hero-slide,.hero-slide .hero-copy>*{transition:none}
  .hero-slide .hero-copy>*{opacity:1;transform:none}
}
.hero-photo{position:absolute;top:0;bottom:0;width:28%;background-size:cover;background-position:center;background-repeat:no-repeat;display:flex;align-items:flex-end;justify-content:center;color:var(--text-on-dark-muted);font-size:var(--text-micro);text-align:center;padding:2rem;z-index:1}
.hero-slide[data-slide="1"] .hero-photo{width:30%}
/* The second slide's left photo is a crate of produce. Centred, the crate sat
   low and the frame cut through the middle of it. Anchored up and to the left
   it enters from the top corner the way the reference composition does, and
   leaves the middle of the band clear for the copy. */
/* Both slides use the same left-hand photograph now, at the owner's direction,
   so the second slide gets no override at all — it inherits the first slide's
   rules and the two are identical by construction rather than by matching two
   sets of numbers. */
.hero-slide[data-slide="1"] .hero-photo.right{background-position:center 30%}
.hero-photo.left{left:0;width:30%}
.hero-photo.right{right:0}
.hero-overlay{position:absolute;inset:0;background:rgba(0,0,0,.08);z-index:2}
/* The copy column was capped at 290px, and 145px on the second slide, which is
   why a six-word heading broke over three lines and the block read as squeezed
   rather than composed. The photos give back a little width to pay for it. The
   cap is still a cap — a hero heading past ~18 words per line stops scanning. */
.hero-copy{position:relative;z-index:3;max-width:min(38vw,560px);text-align:center;color:var(--text-on-dark);padding:0 var(--space-3)}
.hero-copy .eyebrow{font-size:var(--text-small);color:var(--amber-light);margin-bottom:var(--space-2);font-weight:600}
.hero-copy h1,.hero-copy h2{font-size:var(--text-jumbo);line-height:1.15;margin-bottom:var(--space-3);font-weight:700}
.hero-copy .hero-sub{font-size:var(--text-body);line-height:1.55;color:var(--text-on-dark-muted);margin-bottom:var(--space-5);text-wrap:pretty}
.hero-arrow{position:absolute;top:50%;transform:translateY(-50%);width:44px;height:44px;border-radius:50%;background:rgba(255,255,255,.85);border:none;display:flex;align-items:center;justify-content:center;font-size:1.8rem;z-index:3}
.hero-arrow.prev{left:1.6rem}.hero-arrow.next{right:1.6rem}
/* Sits beside the dots, same visual weight as the arrows. Small, because it is
   an escape hatch rather than a feature — but a real button, not an icon glued
   to a div, so it is reachable by keyboard and announces its state. */
.hero-motion{position:absolute;bottom:1.4rem;right:1.6rem;z-index:4;
  width:32px;height:32px;border:none;border-radius:50%;
  background:rgba(255,255,255,.85);color:var(--green-brand);
  font-size:1.3rem;line-height:1;display:flex;align-items:center;justify-content:center;
  transition:background-color .15s ease}
.hero-motion:hover{background:#fff}
.hero-dots{position:absolute;bottom:1.8rem;left:50%;transform:translateX(-50%);display:flex;gap:.8rem;z-index:3}
.hero-dots button{width:9px;height:9px;border-radius:50%;background:rgba(255,255,255,.5);border:none;padding:0}
.hero-dots button.active{background:#fff}

/* ---- category strip ---- */
/* The window the strip travels behind. It owns the vertical padding now, so
   the moving element itself has no box of its own to give away where it is. */
.category-marquee{overflow:hidden;padding:var(--space-6) 0 var(--space-3)}
.category-strip{display:grid;grid-auto-flow:column;grid-auto-columns:min-content;gap:1.6rem;overflow-x:auto;scrollbar-width:none}
.category-strip::-webkit-scrollbar{display:none}
/* Looping is opt-in, added by home.js once it has cloned the tiles and measured
   how far one full set travels. Until then — and if the script never runs — the
   strip is exactly what it was: a row you can scroll by hand.
   The shift is a measured pixel distance rather than -50%, because the track
   carries a gap between every tile including the seam, so half the rendered
   width is half a gap short of the right answer and the loop visibly stutters
   once per cycle. */
/* Looping turns the strip into a rail of identical runs.

   The movement is a percentage of the strip's own width, not a pixel distance,
   and the runs are clones of one element — so one run is exactly one step by
   construction. Three earlier versions measured the track instead (offsetLeft
   plus a gap, then scrollWidth over a count) and each was wrong by a few
   pixels, which is visible once per cycle. There is nothing to measure now.

   The spacing lives on the run as padding rather than between the runs as a
   gap: padding is inside the element's width, so two runs are two identical
   widths with no seam allowance to account for. */
.category-strip.is-looping{overflow:visible;width:max-content;will-change:transform;gap:0;display:flex}
.marquee-run{display:flex;gap:1.6rem;padding-right:1.6rem;flex:0 0 auto}
@media (prefers-reduced-motion:reduce){
  .category-strip.is-looping{animation:none;width:auto;overflow-x:auto}
}
.category-tile{width:120px;background:var(--card-white);border:1px solid var(--input-border);border-radius:var(--radius-card);padding:1.2rem;text-align:center;flex-shrink:0}
.category-tile:hover,.category-tile.active{border:2px solid var(--green-accent);background:var(--green-light)}
.category-tile img{width:64px;height:64px;object-fit:cover;border-radius:8px;margin:0 auto .8rem;background:var(--ceramic)}
.category-tile span{font-size:var(--text-small);font-weight:600}

/* ---- USP row ---- */
.usp-row{background:var(--ceramic);border-radius:var(--radius-card);display:grid;grid-template-columns:repeat(5,1fr);gap:1.6rem;padding:2.8rem}
.usp-item{display:flex;align-items:center;gap:1.4rem}
.usp-icon{width:48px;height:48px;border-radius:50%;border:1.5px solid var(--green-accent);color:var(--green-accent);display:flex;align-items:center;justify-content:center;flex-shrink:0}
.usp-item strong{display:block;font-size:var(--text-small);margin-bottom:.2rem}
.usp-item span{font-size:var(--text-micro);color:var(--text-secondary)}
@media (max-width:1023px){.usp-row{grid-template-columns:repeat(3,1fr)}}
/* One column on a phone. Two columns give each promise 143px, which breaks
   "Farm Fresh Daily" across two lines and "Sourced and delivered same-day"
   across three — five short promises reading as fifteen ragged lines. Stacked,
   each is one line beside its icon. */
@media (max-width:767px){
  .usp-row{grid-template-columns:1fr;gap:var(--space-3);padding:var(--space-4)}
  .usp-item strong{margin-bottom:0}
}

/* ---- section heading ---- */
.section-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:2.4rem;gap:1.6rem;flex-wrap:wrap}
.section-head h2{font-size:var(--text-h2);color:var(--green-brand);font-weight:600}
.carousel-arrows{display:flex;gap:.8rem}
.carousel-arrows button{width:36px;height:36px;border-radius:50%;border:1px solid var(--input-border);background:var(--card-white);display:flex;align-items:center;justify-content:center}
.carousel-arrows button:disabled{opacity:.35;cursor:not-allowed}
.tabs{display:flex;gap:.8rem;flex-wrap:wrap}

/* ---- product card ---- */
.product-grid{display:grid;grid-template-columns:repeat(6,1fr);gap:1.6rem}
.carousel-track{display:flex;gap:1.6rem;overflow-x:auto;scroll-behavior:smooth;scrollbar-width:none;padding-bottom:4px}
.carousel-track::-webkit-scrollbar{display:none}
.carousel-track .product-card{flex:0 0 calc((100% - 5*1.6rem)/6)}
.product-card{background:var(--card-white);border-radius:var(--radius-card);box-shadow:var(--shadow-card);padding:1.6rem;display:flex;flex-direction:column;position:relative;min-width:0}
.product-card .img-wrap{position:relative;aspect-ratio:1/1;border-radius:8px;overflow:hidden;background:var(--neutral-cool);margin-bottom:1.2rem}
.product-card .img-wrap img{width:100%;height:100%;object-fit:cover;opacity:0;transition:opacity .3s ease-in}
.product-card .img-wrap img.loaded{opacity:1}
.product-card.out-of-stock .img-wrap img{opacity:.6!important}
.discount-tag{position:absolute;top:8px;left:8px;background:var(--sale-red);color:#fff;font-size:1.1rem;font-weight:700;padding:.3rem .7rem;border-radius:6px;z-index:2}
.status-badge{position:absolute;top:8px;left:8px;background:var(--green-accent);color:#fff;font-size:1.1rem;font-weight:700;text-transform:uppercase;padding:.3rem .7rem;border-radius:6px;z-index:2}
.origin-badge{position:absolute;bottom:8px;left:8px;background:var(--green-light);color:var(--green-brand);font-size:1.1rem;font-weight:700;text-transform:uppercase;padding:.3rem .7rem;border-radius:6px;z-index:2}
.unit-selector{display:flex;gap:.6rem;margin-bottom:.8rem;flex-wrap:wrap}
.unit-selector button{border-radius:var(--radius-pill);border:1px solid var(--input-border);background:var(--card-white);color:var(--text-primary);font-size:1.2rem;font-weight:600;padding:.4rem 1.2rem}
.unit-selector button.active{background:var(--green-accent);border-color:var(--green-accent);color:#fff}
.product-note{font-size:1.3rem;color:var(--text-secondary);margin-bottom:.6rem}
.price-on-request{font-size:var(--text-small);color:var(--text-secondary);font-weight:600;margin-bottom:.4rem}
.enquire-btn{flex:1;height:36px;border-radius:var(--radius-pill);border:1.5px solid var(--input-border);background:transparent;color:var(--text-primary);font-weight:600;font-size:var(--text-micro);display:flex;align-items:center;justify-content:center}
.wishlist-btn{position:absolute;top:8px;right:8px;width:30px;height:30px;border-radius:50%;background:rgba(255,255,255,.9);border:none;display:flex;align-items:center;justify-content:center;font-size:1.5rem;color:var(--text-secondary);z-index:2}
.wishlist-btn.active{color:var(--sale-red)}
.product-card .p-title{font-size:var(--text-small);font-weight:600;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;min-height:3.6rem;margin-bottom:.4rem}
.product-card .p-unit{font-size:var(--text-micro);color:var(--text-secondary);margin-bottom:.8rem}
.product-card .p-price-row{display:flex;align-items:baseline;gap:.6rem;margin-bottom:.4rem;flex-wrap:wrap}
.product-card .price-now{font-size:1.7rem;font-weight:700;color:var(--sale-red)}
.product-card .price-struck{font-size:var(--text-micro);color:var(--text-secondary);text-decoration:line-through}
.product-card .member-price{font-size:var(--text-micro);color:var(--amber-harvest);font-weight:600;margin-bottom:.6rem}
.stock-line{font-size:var(--text-micro);font-weight:600;margin-bottom:1rem}
.stock-line.in{color:var(--success-green)}
.stock-line.low{color:var(--warning-amber)}
.stock-line.out{color:var(--out-of-stock-gray)}
.card-bottom{display:flex;align-items:center;gap:.8rem;margin-top:auto}
.stepper{display:flex;align-items:center;gap:.6rem;flex-shrink:0}
.stepper button{width:28px;height:28px;border-radius:50%;border:1px solid var(--input-border);background:var(--card-white);display:flex;align-items:center;justify-content:center;font-size:1.4rem;font-weight:700;transition:transform .18s cubic-bezier(.32,2.32,.61,.27)}
.stepper .qty{min-width:20px;text-align:center;font-weight:600;font-size:var(--text-small)}
.add-btn{flex:1;height:36px;border-radius:var(--radius-pill);border:1.5px solid var(--green-accent);background:transparent;color:var(--green-accent);font-weight:600;font-size:var(--text-micro);display:flex;align-items:center;justify-content:center;gap:.5rem;min-width:0}
.add-btn:disabled{border-color:var(--out-of-stock-gray);color:var(--out-of-stock-gray);cursor:not-allowed}
.product-card.out-of-stock .add-btn{opacity:1}

/* compact horizontal card (discounts block, trending) */
.h-card{background:var(--card-white);border-radius:var(--radius-card);box-shadow:var(--shadow-card);padding:1.2rem;display:flex;gap:1.2rem;align-items:center}
.h-card .img-wrap{position:relative;width:76px;height:76px;flex-shrink:0;border-radius:8px;overflow:hidden;background:var(--neutral-cool)}
.h-card .img-wrap img{width:100%;height:100%;object-fit:cover}
.h-card .h-info{flex:1;min-width:0}
.h-card .p-title{font-size:var(--text-small);font-weight:600;margin-bottom:.2rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.h-card .p-unit{font-size:var(--text-micro);color:var(--text-secondary);margin-bottom:.4rem}
.h-card .p-price-row{display:flex;gap:.6rem;align-items:baseline}
.h-card .card-bottom{margin-top:.8rem}

/* trending compact (no add button, clickable) */
.trend-card{display:flex;gap:1.2rem;align-items:center;background:var(--card-white);border-radius:var(--radius-card);box-shadow:var(--shadow-card);padding:1.2rem;border:none;text-align:left;width:100%}
.trend-card .img-wrap{width:64px;height:64px;flex-shrink:0;border-radius:8px;overflow:hidden;background:var(--neutral-cool);position:relative}
.trend-card .img-wrap img{width:100%;height:100%;object-fit:cover}
.trend-card .t-info{min-width:0}
.trend-card .p-title{font-size:var(--text-small);font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.trend-card .p-unit{font-size:var(--text-micro);color:var(--text-secondary);margin:.2rem 0 .4rem}

/* ---- discounts block ---- */
.discounts-block{border:1px solid var(--sale-red);background:hsl(4 82% 43% / 4%);border-radius:var(--radius-card);padding:2.8rem}
.countdown{display:flex;gap:.6rem}
.countdown .unit{background:var(--green-deep);color:#fff;border-radius:8px;padding:.6rem 1rem;font-weight:700;font-size:var(--text-small);min-width:44px;text-align:center}
.discounts-layout{display:grid;grid-template-columns:280px 1fr;gap:1.6rem}
.promo-tile{border-radius:var(--radius-card);padding:2rem;color:#fff;position:relative;overflow:hidden;min-height:150px;display:flex;flex-direction:column;justify-content:center}
.promo-tile.amber{background:var(--amber-harvest)}
.promo-tile.green{background:var(--green-deep)}
.promo-tile .p-name{font-size:var(--text-small);font-weight:600;margin-bottom:.6rem;max-width:65%}
.promo-tile .p-price{font-size:2.4rem;font-weight:700}
.promo-tile .tile-photo{position:absolute;right:-10px;bottom:-10px;width:90px;height:90px;border-radius:50%;background:rgba(255,255,255,.18)}
.discount-grid{display:grid;grid-template-columns:1fr 1fr;gap:1.6rem}

/* ---- weekly section ---- */
.section-ceramic{background:var(--ceramic)}

/* ---- weekend banners ---- */
.banner-row{display:grid;grid-template-columns:repeat(4,1fr);gap:1.6rem}
.promo-banner{border-radius:var(--radius-card);padding:2rem;position:relative;overflow:hidden;min-height:180px;display:flex;flex-direction:column;gap:1rem}
.promo-banner .deal-pill{align-self:flex-start;background:var(--card-white);border-radius:var(--radius-pill);padding:.4rem 1.2rem;font-size:var(--text-micro);font-weight:600;color:var(--green-brand)}
.promo-banner h3{font-size:1.8rem;font-weight:700;line-height:1.25;max-width:65%}
.promo-banner h3 .accent{color:var(--green-accent)}
.promo-banner .banner-photo{position:absolute;right:-16px;bottom:-16px;width:110px;height:110px;border-radius:50%;background:rgba(255,255,255,.35);overflow:hidden}
/* The photo fills the disc rather than sitting in it, so the circle stays the
   shape the design draws and the picture is what changes. The translucent
   background stays underneath as the empty state. */
.promo-banner .banner-photo img{width:100%;height:100%;object-fit:cover;border-radius:50%;transition:transform .5s cubic-bezier(.4,0,.2,1)}
.promo-banner:hover .banner-photo img{transform:scale(1.06)}
@media (prefers-reduced-motion:reduce){.promo-banner .banner-photo img{transition:none}.promo-banner:hover .banner-photo img{transform:none}}
.promo-banner.tint-1{background:var(--green-light)}
.promo-banner.tint-2{background:var(--amber-lightest)}
.promo-banner.tint-3{background:var(--ceramic)}
.promo-banner.tint-4{background:var(--neutral-cool)}

/* ---- blog ---- */
.blog-row{display:grid;grid-template-columns:repeat(4,1fr);gap:1.6rem}
.blog-card img{width:100%;aspect-ratio:3/2;object-fit:cover;border-radius:var(--radius-card);margin-bottom:1.2rem;background:var(--ceramic)}
.blog-card .meta{font-size:var(--text-small);color:var(--text-secondary);margin-bottom:.8rem}
.blog-card h3{font-family:var(--font-serif);font-size:2rem;font-weight:600;margin-bottom:1.2rem}

/* ---- footer ---- */
.site-footer{background:var(--green-deep);color:var(--text-on-dark);padding:var(--space-9) 0 var(--space-4)}
.footer-cols{display:grid;grid-template-columns:1.2fr 1fr 1fr 1fr 1.2fr;gap:2.4rem;margin-bottom:var(--space-6)}
.footer-cols h4{color:#fff;font-size:1.6rem;font-weight:600;margin-bottom:1.6rem}
.footer-cols a{color:var(--text-on-dark-muted);font-size:var(--text-small);display:block;margin-bottom:1rem}
.footer-phone{color:var(--green-light);font-size:2rem;font-weight:700;margin:1rem 0}
.footer-cols .hours{color:var(--text-on-dark-muted);font-size:var(--text-small);margin-bottom:.6rem}
.newsletter-input-row{display:flex;gap:.8rem;margin:1.2rem 0}
.newsletter-input-row input{flex:1;height:44px;border-radius:var(--radius-pill);border:none;padding:0 1.6rem;font-size:var(--text-small)}
.newsletter-input-row button{flex-shrink:0}
.consent-line{font-size:var(--text-micro);color:var(--text-on-dark-muted);display:flex;gap:.6rem;align-items:flex-start}
.footer-bottom{border-top:1px solid rgba(255,255,255,.15);padding-top:2.4rem;display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:1.6rem}
.social-icons{display:flex;gap:1.2rem}
.social-icons a{width:36px;height:36px;border-radius:50%;border:1px solid rgba(255,255,255,.25);display:flex;align-items:center;justify-content:center;color:#fff}
.payment-icons{display:flex;gap:1rem;color:var(--text-on-dark-muted);font-size:var(--text-micro)}
.footer-accordion-toggle{display:none}

/* ---- floating cart ---- */
.fab-cart{position:fixed;bottom:2.8rem;right:2.8rem;width:56px;height:56px;border-radius:50%;background:var(--green-accent);color:#fff;border:none;display:flex;align-items:center;justify-content:center;box-shadow:var(--shadow-fab-base),var(--shadow-fab-ambient);z-index:80}
.fab-cart:active{box-shadow:var(--shadow-fab-base)}

/* ---- cart drawer ---- */
.overlay-scrim{position:fixed;inset:0;background:rgba(0,0,0,.4);z-index:90;display:none}
.overlay-scrim.open{display:block}
.cart-drawer{position:fixed;top:0;right:0;bottom:0;width:420px;max-width:100vw;background:var(--card-white);z-index:95;transform:translateX(100%);transition:transform .3s ease;display:flex;flex-direction:column;box-shadow:var(--shadow-sheet)}
.cart-drawer.open{transform:translateX(0)}
.drawer-head{display:flex;align-items:center;justify-content:space-between;padding:2rem;border-bottom:1px solid var(--input-border)}
.drawer-body{flex:1;overflow-y:auto;padding:1.6rem 2rem}
.cart-line{display:flex;gap:1.2rem;padding:1.2rem 0;border-bottom:1px solid var(--table-hairline,#E7E7E7)}
.cart-line img{width:64px;height:64px;object-fit:cover;border-radius:8px;background:var(--ceramic)}
.cart-line .cl-info{flex:1;min-width:0}
.cart-line .cl-title{font-size:var(--text-small);font-weight:600}
.cart-line .cl-remove{font-size:var(--text-micro);color:var(--sale-red);background:none;border:none;padding:0;margin-top:.4rem}
.drawer-footer{padding:2rem;border-top:1px solid var(--input-border)}
.progress-track{height:8px;border-radius:var(--radius-pill);background:var(--ceramic);overflow:hidden;margin:.8rem 0 1.6rem}
.progress-fill{height:100%;background:var(--green-accent);border-radius:var(--radius-pill);transition:width .3s ease}
.subtotal-row{display:flex;justify-content:space-between;margin-bottom:.6rem;font-size:var(--text-body)}
.savings-row{color:var(--green-accent);font-weight:600;font-size:var(--text-small);margin-bottom:1.2rem}

/* ---- toast ---- */
.toast-wrap{position:fixed;bottom:2.4rem;left:50%;transform:translateX(-50%);z-index:100;display:flex;flex-direction:column;gap:.8rem}
.toast{background:var(--green-deep);color:#fff;padding:1.2rem 2rem;border-radius:var(--radius-pill);font-size:var(--text-small);box-shadow:var(--shadow-nav);animation:toast-in .25s ease}
@keyframes toast-in{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}}

/* ---- by-origin row ---- */
.origin-row{display:grid;grid-template-columns:repeat(4,1fr);gap:1.6rem}
.origin-card{background:var(--card-white);border-radius:var(--radius-card);box-shadow:var(--shadow-card);padding:2rem;text-align:center;border:none;cursor:pointer}
.origin-card.active{border:2px solid var(--green-accent);background:var(--green-light)}
/* The ceramic fill stays as the empty state — a group whose representative
   product has gone still gets a well-formed tile, not a broken image. */
.origin-card .o-photo{aspect-ratio:1/1;border-radius:8px;background:var(--ceramic);margin-bottom:1.2rem;overflow:hidden}
.origin-card .o-photo img{width:100%;height:100%;object-fit:cover;display:block;transition:transform .5s cubic-bezier(.4,0,.2,1)}
.origin-card:hover .o-photo img{transform:scale(1.05)}
@media (prefers-reduced-motion:reduce){.origin-card .o-photo img{transition:none}.origin-card:hover .o-photo img{transform:none}}
.origin-card strong{display:block;font-size:var(--text-body);margin-bottom:.2rem}
.origin-card span{font-size:var(--text-micro);color:var(--text-secondary)}
@media (max-width:767px){.origin-row{grid-template-columns:repeat(2,1fr)}}

/* ---- shop page layout ---- */
.shop-layout{display:grid;grid-template-columns:260px 1fr;gap:2.4rem;align-items:start}
.shop-sidebar{background:var(--card-white);border-radius:var(--radius-card);box-shadow:var(--shadow-card);padding:2rem;position:sticky;top:90px}
.filter-group{border-bottom:1px solid var(--input-border);padding-bottom:1.6rem;margin-bottom:1.6rem}
.filter-group:last-child{border-bottom:none}
.filter-group-head{display:flex;justify-content:space-between;align-items:center;background:none;border:none;width:100%;font-size:var(--text-small);font-weight:700;padding:0 0 1rem;color:var(--text-primary)}
.filter-option{display:flex;align-items:center;gap:.8rem;font-size:var(--text-small);padding:.5rem 0;cursor:pointer}
.filter-sub-list{padding-left:1rem}
.filter-sub-list.collapsed{display:none}
.filter-option-row{display:flex;align-items:center;gap:.4rem}
.filter-option-row .filter-option{flex:1}
.sub-expand-toggle{background:none;border:none;color:var(--text-secondary);font-size:1.1rem;padding:.4rem;transition:transform .2s ease}
.sub-expand-toggle.open{transform:rotate(180deg)}
.filter-item-list{padding-left:2.6rem}
.filter-item-list.collapsed{display:none}
.filter-option-nested{font-size:1.3rem;padding:.35rem 0}
.price-slider{width:100%;accent-color:var(--green-accent);margin:.8rem 0}
.shop-toolbar{display:flex;justify-content:space-between;align-items:center;margin-bottom:2rem;gap:1.6rem;flex-wrap:wrap}
.result-count{font-size:var(--text-small);color:var(--text-secondary)}
.sort-select{border:1px solid var(--input-border);border-radius:var(--radius-field);height:40px;padding:0 1.2rem;font-size:var(--text-small);background:var(--card-white)}
.shop-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:1.6rem;transition:opacity .2s ease}
/* Cleared above the bottom tab bar, which is 60px of fixed furniture at this
   size. At 2.4rem the button sat on top of the Search tab — measured overlap
   36px — so the two controls occupied the same thumb. */
/* Right-aligned, not centred. Centred it landed exactly on the Add buttons of
   the two cards in the bottom row — measured at 320px, it covered both — so the
   one control a shopper reaches for most was the one thing they could not tap.
   Against the right edge it overlaps the margin of one card instead. */
.filters-fab{display:none;position:fixed;bottom:calc(60px + var(--space-3));right:var(--gutter-mobile);z-index:80}
.filter-sheet-scrim{position:fixed;inset:0;background:rgba(0,0,0,.4);z-index:90;display:none}
.filter-sheet-scrim.open{display:block}
.filter-sheet{position:fixed;left:0;right:0;bottom:0;background:var(--card-white);border-radius:var(--radius-sheet-top);z-index:95;max-height:80vh;overflow-y:auto;transform:translateY(100%);transition:transform .3s ease;padding:2rem}
.filter-sheet.open{transform:translateY(0)}
/* This rule used to sit near the end of the file. Being later in the cascade it
   beat the 767px and 479px rules below at every width they cared about, so a
   320px phone was laying products out three across — 96px a card, too narrow
   for the price and the add button, which is what pushed the stepper out of the
   card. Same rule, moved above the ones that must override it. */
@media (max-width:1439px){.shop-grid{grid-template-columns:repeat(3,1fr)}}
@media (max-width:1023px){.shop-grid{grid-template-columns:repeat(3,1fr)}}
@media (max-width:767px){
  .shop-layout{grid-template-columns:1fr}
  .shop-sidebar{display:none}
  .shop-grid{grid-template-columns:repeat(2,1fr)}
  .filters-fab{display:block}
}

/* ---- mobile bottom tabs ---- */
.bottom-tabs{display:none}

/* ============ responsive ============ */
@media (max-width:1439px){
  .product-grid{grid-template-columns:repeat(4,1fr)}
  .carousel-track .product-card{flex:0 0 calc((100% - 3*1.6rem)/4)}
  .hero-copy h1,.hero-copy h2{font-size:var(--text-hero-lg)}
}
@media (max-width:1023px){
  /* Tablet: the two side photos stop earning their width once the copy needs
     it, so they narrow and the copy column is free to use the middle. */
  .hero-copy{max-width:min(56vw,520px)}
  .hero-photo,.hero-slide[data-slide="1"] .hero-photo,
  .hero-photo.left,.hero-slide[data-slide="1"] .hero-photo.left{width:22%}
  .container{padding:0 var(--gutter-tablet)}
  .product-grid{grid-template-columns:repeat(3,1fr)}
  .carousel-track .product-card{flex:0 0 calc((100% - 2*1.6rem)/3)}
  .banner-row{grid-template-columns:repeat(2,1fr)}
  .discounts-layout{grid-template-columns:1fr}
  .discount-grid{grid-template-columns:1fr 1fr}
  .blog-row{grid-template-columns:1fr 1fr}
  .footer-cols{grid-template-columns:1fr 1fr}
  .footer-cols>div:first-child{grid-column:1/-1}
  .header-actions .action span:last-child{display:none}
}
@media (max-width:767px){
  .container{padding:0 var(--gutter-mobile)}
  .section{padding-block:var(--space-5)}
  .product-grid{grid-template-columns:repeat(2,1fr)}
  .carousel-track .product-card{flex:0 0 calc((100% - 1.6rem)/2)}
  /* Two cards across a 390px phone leaves about 171px a card. The stepper is a
     fixed ~90px of that, so the Add button was being handed roughly 70px and its
     label was cut off mid-word. Let the row wrap: the stepper keeps the first
     line, the button takes the whole of the second and is readable again. */
  .card-bottom{flex-wrap:wrap;row-gap:.8rem}
  .card-bottom .add-btn{flex:1 0 100%}
  /* Phone: the slide is now heading + sentence + button, so 340px cropped it.
     The side photos shrink to a framing strip and the copy takes the rest. */
  .hero-slider{height:420px}
  .hero-copy h1,.hero-copy h2{font-size:var(--text-hero-lg)}
  /* The side photos are 14% each at this size. max-width:none let the copy span
     the full 390px, so the sentence ran straight across the delivery photograph
     and became unreadable. Inset past both. */
  /* The copy now sits ON the photograph rather than beside it — see the scrim
     below. It only has to clear the part of the picture that is still legible. */
  .hero-copy{max-width:none;padding:0 34% 0 var(--space-3)}
  /* The arrows sit 1.6rem from each edge, which is exactly where the copy now
     starts — the left one was landing on top of the first word. The dots are
     tappable, the slideshow advances by itself, and there is a pause control:
     the arrows are the one part of that set a phone can do without. */
  .hero-arrow{display:none}
  /* The heading gets the full column; the sentence is pulled in to a shorter
     measure so its longest line stops short of the figure rather than running
     into the bag he is holding. Centred, so it stays centred. */
  .hero-copy .hero-sub{font-size:var(--text-small);margin:0 auto var(--space-4);max-width:26ch}
  /* 14% of a 390px phone is 55px. Measured in a real browser: the right-hand
     photograph still reads at that width — a face and a crate — but the left one
     is anchored to its own right edge and shows nothing but background, so it
     was 55px of plain green pretending to be a picture. Drop it and give the
     one that works a little more room. */
  .hero-photo.left,.hero-slide[data-slide="1"] .hero-photo.left{display:none}
  /* 22% of a 390px phone is 86px, and the photograph is a standing person. At
     that width the frame ran down the middle of his face: a vertical slice of a
     cheek, half a cap and part of a box. It read as a rendering fault rather
     than as a picture, which is what "the hero does not look premium" was.

     So: give it 62% and let the copy sit over it, with a scrim doing the work
     the hard edge used to. Because the slot is now taller than it is wide
     relative to the source, `cover` binds on height and the whole figure is in
     frame, head to feet, instead of being cropped to a strip. */
  .hero-photo.right,.hero-slide[data-slide="1"] .hero-photo.right{width:62%;padding:0;background-position:center top}
  /* The scrim. Solid brand green under the copy, clearing to nothing by the
     right-hand edge, so the photograph emerges out of the background instead of
     being butted against it. z-index 2 puts it over the photo (1) and under the
     copy (3). */
  /* Slide 2's photograph is a man standing behind a crate, so half its height
     is crate and `cover` — which fits the whole frame — leaves him small. The
     first slide's figure is a man holding a box at chest height and fills the
     frame on his own. Scaling slide 2 to 132% of the slot height and anchoring
     to the top crops the bottom of the crate and brings him up to the same
     size. Measured, not guessed: both cut-outs fill ~86% x ~92% of their own
     canvas, so the difference was never in the files. */
  .hero-slide[data-slide="1"] .hero-photo.right{background-size:auto 132%;background-position:54% top}
  .hero-photo.right::after{content:"";position:absolute;inset:0;z-index:2;
    background:linear-gradient(90deg,
      var(--green-deep) 0%,
      var(--green-deep) 22%,
      rgba(16,53,43,.93) 46%,
      rgba(16,53,43,.42) 70%,
      rgba(16,53,43,0) 92%)}
  .banner-row{grid-template-columns:1fr}
  .discount-grid{grid-template-columns:1fr}
  .blog-row{grid-template-columns:1fr}
  /* Measured at 390x844: announcement bar, header row and search bar came to
     197px of chrome — nearly a quarter of the screen — before the hero started.
     The header row itself was 1.6rem of padding above and below a 36px logo,
     and the search bar sat a further 1.6rem below that. Tightening both gives
     the hero back about 30px without making anything harder to tap; the search
     field keeps its 44px height, which is the part that matters. */
  .site-header{padding:1rem 0}
  /* Measured across six phone widths: the top row wants 333px — a 44px
     hamburger, an 85px logo, 172px of actions and two 16px gaps. A 360px phone
     gives the container 328px, so it wrapped and the three icons dropped onto a
     row of their own, left-aligned under the logo. It looked broken because it
     was: 5px short.

     Everything below buys back that 5px and a good deal more, without touching
     a tap target. The buttons stay 44px; only the air between them goes. */
  .site-header .container{flex-wrap:wrap;row-gap:1rem;gap:1.2rem;justify-content:space-between}
  .header-actions{gap:.8rem;margin-left:auto}
  .search-wrap{order:3;flex-basis:100%}
  .announcement-bar{padding:.7rem 0}
  .cat-btn span{display:none}
  /* minmax(0,1fr), not 1fr. A 1fr track is minmax(auto,1fr) and auto refuses to
     go below the widest item's min-content — the newsletter's input and button
     come to 319px side by side, so the single track was forced to 327 inside a
     288 container and every column overflowed with it. That is why the footer
     phone number looked like the problem: it was only filling a column that had
     already been pushed too wide. */
  .footer-cols{grid-template-columns:minmax(0,1fr);grid-row-gap:0}
  /* --space-9 above the logo is 64px of empty dark green before anything is
     said. That reads as generous on a 1440px page and as a gap on a phone. */
  /* The tab bar is fixed and 60px tall, and body carries no bottom padding at
     this width, so the last 60px of every page sat behind it — which is where
     the small print and the design credit live. The footer pays for the bar it
     is sitting under. */
  .site-footer{padding-top:var(--space-6);padding-bottom:calc(var(--space-6) + 60px)}
  /* Each column already carries its own rule and spacing at this width, so the
     block's own bottom margin stacked on top of the last one and left about
     70px of empty dark green between the newsletter and the small print. */
  .footer-cols{margin-bottom:0}
  /* And let the subscribe row stack rather than demand its 319px. */
  .newsletter-input-row{flex-wrap:wrap}
  .newsletter-input-row input,.newsletter-input-row .pill-btn{flex:1 1 100%}
  .footer-cols>div{border-bottom:1px solid rgba(255,255,255,.15);padding-bottom:1.2rem;margin-bottom:1.2rem}
  /* Open by default. Collapsed-by-default hid all nineteen footer links behind
     four plus signs, so a phone saw a footer with no links in it at all — the
     one place a visitor looks for the pages that are not in the menu. The
     toggle still closes a section for anyone who wants it shorter. */
  .footer-cols .col-links{display:block}
  .footer-cols .col-links.collapsed{display:none}
  /* No extra border here: the rule above already gives every column a
     border-bottom, and adding a border-top drew a second line with a gap
     between the two. A modest tap target instead — the base rule spaces links
     by margin alone, which is under 30px on a touch screen. */
  .footer-cols .col-links a{padding:.35rem 0;margin-bottom:.6rem}
  .footer-cols h4.desktop-only{display:none}
  .footer-accordion-toggle{display:flex;justify-content:space-between;align-items:center;width:100%;background:none;border:none;color:#fff;padding:0;margin-bottom:1.2rem}
  .fab-cart{bottom:8.4rem}
  .bottom-tabs{display:flex;position:fixed;bottom:0;left:0;right:0;background:var(--card-white);box-shadow:var(--shadow-nav);z-index:70;padding:.8rem 0}
  /* .bottom-tabs is a flex row, so .container was a flex item and shrank to its
     content — 185px of a 390px bar, with the five labels touching each other.
     flex:1 makes it fill the bar again. */
  .bottom-tabs .container{display:flex;justify-content:space-between;padding:0 1.6rem;flex:1;max-width:none}
  .bottom-tabs a{display:flex;flex-direction:column;align-items:center;gap:.3rem;font-size:1rem;color:var(--text-secondary);min-height:44px;justify-content:center}
  body{padding-bottom:0}
}
@media (max-width:479px){
  /* Two cards a row, not one. One card a row measured 358x580 on a 390px phone
     — a single product filling two thirds of the screen, which is what "products
     are far too big" meant. Two across is 171px a card and shows four products
     in the space one used to take.

     The card was designed for a 340px desktop column, so at 171px every part of
     it needs to come down a step: the photo loses its padding frame, the name
     drops to small, the unit buttons and price shrink, and the internal gaps
     halve. Below the grid rules so these win. */
  /* 78% of a 390px phone is 279px. The grid two sections below it renders the
     same card at 171px, so "Fresh Today" showed cards two thirds larger than
     everything else on the page and only one and a bit fitted on screen. Same
     width as the grid, so a card is a card wherever it appears. */
  .carousel-track .product-card{flex:0 0 calc((100% - 1.6rem)/2)}
  /* Measured at 320px: the number renders 327px wide inside a 288px column and
     pushes the whole footer out. It is the largest text on the page and has no
     need to be. */
  .footer-phone{font-size:var(--text-body-lg)}

  .product-card{padding:.8rem;gap:.4rem}
  .product-card .img-wrap{padding:0;margin-bottom:.6rem}
  .product-card .p-title{font-size:var(--text-small);line-height:1.3}
  .product-card .p-unit{font-size:var(--text-micro)}
  /* The one-line description ran to three lines in a 171px card and was the
     single biggest thing in it — taller than the photograph. The product page
     carries it in full; a grid is for choosing between products, and the name,
     unit and price do that. */
  .product-card .product-note{display:none}
  .product-card .price-now{font-size:var(--text-body-lg)}
  .product-card .price-was{font-size:var(--text-micro)}
  .product-card .unit-selector{gap:.3rem;margin:.4rem 0}
  .product-card .unit-selector button{padding:.3rem .6rem;font-size:var(--text-micro)}
  .product-card .origin-badge,.product-card .status-badge{font-size:1rem;padding:.2rem .5rem}
  .product-card .wishlist-btn{width:32px;height:32px}
  /* The stepper and the Add button get a line each. They were put on one line
     to save height, and the arithmetic does not work: pages.css grows the
     stepper circles to 38px for the sake of a thumb-sized target, so the
     stepper occupies 106px of a card that is 156px wide on a 360px phone. That
     left the Add button 30px — measured — and the word "Add" spilled out past
     the rounded edge, which is what it looked like on a real handset.

     Three 38px targets and a button cannot share 140px, and shrinking the
     circles to make them fit would undo a deliberate accessibility decision.
     So the row wraps: the stepper keeps its targets, and Add becomes a
     full-width control, which is a better thing to aim at than a sliver
     anyway. Costs about 44px of card height. */
  .card-bottom{flex-wrap:wrap;row-gap:.6rem;gap:.4rem}
  .card-bottom .add-btn{flex:1 0 100%;padding:.8rem .6rem;font-size:var(--text-small)}
  .stepper{flex:0 0 auto}
  .stepper .qty{min-width:20px;font-size:var(--text-small)}
}
