/* Ziventa Nutriments - site styles.
   Extracted from landing.html so every page shares one cached copy
   instead of inlining 67KB each. The two blocks are concatenated in
   their original order, so the cascade is exactly as it was. */

:root{
  --cream:#FBF6EC;
  --cream-alt:#F6EFDF;
  --ink:#2F4A3D;
  --ink-soft:#6E5F4E;
  --gold:#BF8F3A;
  --gold-deep:#8F6A1E;
  --green:#3F6B52;
  --green-deep:#24382D;
  --green-tint:#F6EFDF;
  --card-bg:#FFFDF8;
  --maroon:#5C201D;
  --border:rgba(59,45,30,0.12);
  --shadow:0 10px 28px rgba(59,45,30,0.08);
  --radius:20px;
  --font-display:Georgia,'Iowan Old Style','Palatino Linotype','Book Antiqua',serif;
  --font-body:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;
}
*{box-sizing:border-box;}
[hidden]{display:none !important;}
/* Stop the page scrolling sideways. Reported on Android, fine on iOS.

   This was `overflow-x:clip` on <html> alone. `clip` is the better of the
   two - unlike `hidden` it does not turn the element into a scroll container,
   which is what breaks position:sticky - but a browser that does not know the
   value throws the whole declaration away, and then nothing stops the page
   scrolling sideways at all. iOS Safari has understood it since 16 and
   Android Chrome since 90, but Samsung Internet - the default browser on a
   lot of Android phones - only from 15. That is the split.

   So `hidden` first for everyone, then `clip` for browsers that support it,
   and on both elements because setting it on <html> alone is unreliable on
   several Android browsers.

   Worth saying: nothing of ours is actually cut off by this. Audited at every
   width from 320 to 1920 and no element genuinely overflows - the wide
   marquee is already clipped by .trust-strip, and the cart and nav drawers
   are position:fixed. What was scrolling into view was empty space. */
html,body{overflow-x:hidden;}
html{scroll-behavior:smooth;}
@supports (overflow-x:clip){
  html,body{overflow-x:clip;}
}
body{
  margin:0;
  background:var(--cream);
  color:var(--ink);
  font-family:var(--font-body);
  line-height:1.6;
  -webkit-font-smoothing:antialiased;
}
img{max-width:100%;display:block;}
h1,h2,h3{font-family:var(--font-display);color:var(--ink);line-height:1.15;margin:0 0 .5em;}
p{margin:0 0 1em;color:var(--ink-soft);}
a{color:inherit;}
.skip-link{position:absolute;left:-999px;top:0;background:var(--gold);color:#fff;padding:.75em 1em;border-radius:0 0 8px 0;z-index:200;}
.skip-link:focus{left:0;}

/* scroll progress */
.scroll-progress{position:fixed;top:0;left:0;right:0;height:3px;z-index:300;background:transparent;pointer-events:none;}
.scroll-progress span{
  display:block;height:100%;width:0%;
  background:linear-gradient(90deg, var(--gold-deep), var(--gold));
  box-shadow:0 0 10px rgba(191,143,58,.5);
}

/* blur-up image loading */
img[data-blur]{filter:blur(14px);transform:scale(1.03);transition:filter .7s ease, transform .7s ease;}
img[data-blur="loaded"]{filter:blur(0);transform:scale(1);}

.section-kicker{
  text-transform:uppercase;letter-spacing:.12em;font-size:.78rem;font-weight:600;
  color:var(--gold-deep);margin:0 0 .6em;
}
.section-head{max-width:640px;margin:0 auto 1.5rem;text-align:center;padding:0 1.5rem;}
.section-sub{max-width:560px;margin:0 auto;}

.js .reveal{opacity:0;transform:translateY(24px);}
/* The finished state is DECLARED, not just animated to.
 *
 * This rule used to be the animation alone, which made every section's
 * visibility depend on that animation actually running. Anything that stops
 * it - a suspended tab, a restored back/forward page, a browser that skips
 * animations on a hidden or throttled document - left the element at the
 * opacity:0 above with nothing to move it, and the section stayed blank with
 * no error to explain why.
 *
 * Declared first, animated second: a running animation still overrides these
 * values, so the fade plays exactly as before, and if it never runs the
 * content is simply there. The same inversion the order receipt already uses,
 * for the same reason. */
/* `both`, not `forwards`, and that is load-bearing now that opacity:1 is
 * declared above. These elements get an animation-delay of up to 420ms to
 * stagger them. With `forwards` the animation applies nothing during that
 * delay, so the declared opacity:1 would show the element, and the animation
 * would then snap it back to 0 and fade it in - a visible flash on every
 * staggered card. `both` fills the 0% keyframe backwards through the delay,
 * so it stays hidden until its turn, exactly as before. */
.js .reveal.in-view{opacity:1;transform:none;animation:revealIn .7s ease both;}
/* No IntersectionObserver means nothing will ever add .in-view, so show
   everything at once. Same rules as the <noscript> block near the top - that
   one covers JS being off, this one covers JS being on without the API. */
.no-io .reveal{opacity:1 !important;transform:none !important;}
.no-io .gallery-item.reveal{clip-path:none !important;}
.no-io .scroll-progress{display:none;}
@keyframes revealIn{from{opacity:0;transform:translateY(24px);}to{opacity:1;transform:translateY(0);}}

.btn{
  display:inline-flex;align-items:center;gap:.5em;
  padding:.9em 1.6em;border-radius:999px;font-weight:600;font-size:.98rem;
  text-decoration:none;border:1px solid transparent;cursor:pointer;
  transition:transform .18s ease, box-shadow .18s ease, background .18s ease;
  font-family:var(--font-body);
}
.btn svg{width:18px;height:18px;}
.btn-primary{background:var(--gold);color:#fff;box-shadow:0 8px 20px rgba(191,143,58,.28);}
.btn-primary:hover{transform:translateY(-2px);box-shadow:0 12px 24px rgba(191,143,58,.35);}
.btn-ghost{background:transparent;border-color:var(--border);color:var(--ink);}
.btn-ghost:hover{border-color:var(--gold);color:var(--gold-deep);}
.btn-block{width:100%;justify-content:center;}
.text-link{display:inline-flex;align-items:center;gap:.4em;color:var(--gold-deep);font-weight:600;text-decoration:none;}
.text-link svg{width:16px;height:16px;}
.text-link:hover{text-decoration:underline;}

/* header */
.site-header{
  position:sticky;top:0;z-index:100;
  /* Solid first, translucent second. color-mix() is recent - Chrome 111,
     Safari 16.2, Firefox 113 - and this is the header's ONLY background, so
     a browser that drops the declaration gets a transparent bar with the page
     scrolling through the nav text. rgba says the same thing everywhere and
     is overridden below wherever color-mix is understood. */
  background:rgba(251,246,236,.88);
  background:color-mix(in srgb, var(--cream) 88%, transparent);
  -webkit-backdrop-filter:blur(10px);
  backdrop-filter:blur(10px);
  border-bottom:1px solid var(--border);
  transition:box-shadow .2s ease;
}
/* Without blur the bar needs to be opaque, or text shows through it. */
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .site-header{background:var(--cream);}
}
.site-header.scrolled{box-shadow:0 8px 24px rgba(0,0,0,.08);}
.header-inner{
  max-width:1060px;margin:0 auto;padding:.9rem 1.5rem;
  display:flex;align-items:center;justify-content:space-between;
}
/* Brand lockup: the Ziventa wordmark with "Gaushala" set beneath it.

   The logo is an SVG file rather than inline paths so there is exactly one
   copy of it, shared by the header, the footer and the React pages - change
   the file and every lockup follows.

   width/height on the <img> are the artwork's own proportions (329x86). They
   are never the displayed size; they are there so the browser reserves the
   right space before the SVG loads and the nav does not jump. */
.brand{display:inline-flex;align-items:center;gap:.52em;text-decoration:none;}
/* The symbol carries alt="" - it is decorative here, because the wordmark
   beside it already supplies the accessible name and the <a> has its own
   label. Two "Ziventa"s would just be read out twice. */
.brand-symbol{width:38px;height:38px;display:block;flex-shrink:0;}
.brand-words{display:inline-flex;flex-direction:column;align-items:center;gap:.14em;}
.brand-logo{height:26px;width:auto;display:block;}
.brand-sub{
  font-family:var(--font-body);font-size:.56rem;font-weight:600;
  letter-spacing:.42em;text-transform:uppercase;color:var(--gold-deep);
  /* The trailing letter-space pushes the word off-centre; pull it back. */
  margin-right:-.42em;line-height:1;
}
.main-nav{display:flex;align-items:center;gap:1.6rem;}
.nav-link{
  position:relative;text-decoration:none;color:var(--ink-soft);font-weight:500;font-size:.94rem;
  padding:.3em 0;
}
.nav-link::after{
  content:"";position:absolute;left:0;right:100%;bottom:-2px;height:2px;background:var(--gold);
  transition:right .25s ease;
}
.nav-link:hover,.nav-link.active{color:var(--ink);}
.nav-link.active::after,.nav-link:hover::after{right:0;}
.nav-cta{
  background:var(--gold);color:#fff;padding:.6em 1.3em;border-radius:999px;text-decoration:none;
  font-weight:600;font-size:.9rem;transition:background .2s ease;
}
.nav-cta:hover{background:var(--gold-deep);}
.nav-toggle{
  display:none;background:none;border:1px solid var(--border);border-radius:10px;
  width:42px;height:42px;align-items:center;justify-content:center;cursor:pointer;color:var(--ink);position:relative;
}
.nav-toggle svg{width:20px;height:20px;position:absolute;transition:opacity .15s ease,transform .15s ease;}
.nav-toggle .icon-close{opacity:0;transform:scale(.7);}
.nav-toggle[aria-expanded="true"] .icon-open{opacity:0;transform:scale(.7);}
.nav-toggle[aria-expanded="true"] .icon-close{opacity:1;transform:scale(1);}

/* trust strip */
/* "You're not signed in" strip, above the membership form and in checkout. */
.signin-strip{
  display:flex;align-items:center;justify-content:space-between;gap:.75rem;flex-wrap:wrap;
  margin:0 0 1rem;padding:.7rem .9rem;border-radius:.6rem;
  background:rgba(191,143,58,.10);border:1px solid rgba(191,143,58,.35);
  font-size:.88rem;color:var(--ink);
}
.signin-strip.is-in{background:rgba(30,74,53,.08);border-color:rgba(30,74,53,.25);}
.signin-strip a{
  flex:none;text-decoration:none;font-weight:600;
  padding:.4rem .9rem;border-radius:.45rem;
  background:var(--green-deep,#1E4A35);color:var(--cream);
}
.signin-strip a:hover{opacity:.9;}
.signin-strip .si-note{flex:1;min-width:12rem;}

.trust-strip{background:var(--maroon);overflow:hidden;padding:.7rem 0;}
.trust-track{display:flex;width:max-content;gap:2.5rem;padding:0 1.25rem;animation:trustScroll 28s linear infinite;white-space:nowrap;}
.trust-track span{color:var(--cream);font-size:.8rem;font-weight:600;letter-spacing:.04em;text-transform:uppercase;}
.trust-track .dot{color:var(--gold);font-weight:700;margin:0 .1em;}
@keyframes trustScroll{from{transform:translateX(0);}to{transform:translateX(-50%);}}

/* hero */
.hero{
  padding:2.75rem 1.5rem clamp(165px,21vw,255px);text-align:center;position:relative;overflow:hidden;
  min-height:min(76vh,680px);min-height:min(76dvh,680px);display:flex;align-items:center;justify-content:center;
}

/* Ziventa logo lockup */
.hero-logo{
  display:flex;flex-direction:column;align-items:center;
  margin:0 auto 1.1rem;line-height:1;
}
.hero-logo-mark{
  width:clamp(204px,29vw,312px);height:auto;display:block;
}
.hero-logo-tag{
  display:flex;align-items:center;gap:.7em;
  margin-top:.55em;
  font-size:clamp(.62rem,1.1vw,.78rem);
  text-transform:uppercase;letter-spacing:.3em;
  color:#1c4a23;font-weight:600;
}
.hero-logo-tag i{display:block;width:clamp(14px,2.4vw,26px);height:1.5px;background:#1c4a23;opacity:.75;}

/* Hero entrance choreography.
   Sequenced rather than a single banner pop: the lockup settles, the tagline
   breathes outward, then each line rises 16px in turn. Nothing is opacity:0 in
   the base rules, so the hero still reads if animations never run. */
.hero-inner > *{animation:zhRise .72s cubic-bezier(.22,.85,.3,1) both;}
.hero-logo{animation:zhStamp .85s cubic-bezier(.22,.9,.28,1) both;}
.hero-logo-tag{animation:zhSpread 1.15s cubic-bezier(.3,.85,.3,1) both .34s;}
.hero-inner .eyebrow{animation-delay:.32s;}
.hero-inner h1{animation-delay:.42s;}
.hero-lede{animation-delay:.52s;}
.hero-actions{animation-delay:.62s;}
.hero-note{animation-delay:.72s;}
@keyframes zhRise{from{opacity:0;transform:translateY(16px);}to{opacity:1;transform:none;}}
@keyframes zhStamp{from{opacity:0;transform:scale(.955);}to{opacity:1;transform:none;}}
@keyframes zhSpread{from{opacity:0;letter-spacing:.14em;}to{opacity:1;letter-spacing:.3em;}}

/* Dawn wash over the pasture. Scale runs 1.035 -> 1 and never below 1, so the
   scene cannot uncover the page edges the way a letterboxed fit would. */
.hero-scene{animation:zhDawn 1.9s cubic-bezier(.25,.7,.3,1) both;}
@keyframes zhDawn{from{opacity:0;transform:scale(1.035);}to{opacity:1;transform:none;}}

/* A directional nudge on the primary CTA arrow instead of a vertical bob. */
.hero-actions .btn-primary svg,.hero-actions .btn-primary i{animation:zhNudge 2.8s ease-in-out infinite;}
@keyframes zhNudge{0%,72%,100%{transform:translateX(0);}42%{transform:translateX(3px);}}


/* illustrated pasture scene */
.hero-scene{
  position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;pointer-events:none;
}
.hero-scene svg{width:100%;height:100%;display:block;}
.zf-sky{fill:url(#zgSky);}
.zf-sun{fill:url(#zgSun);animation:zSunBreathe 11s ease-in-out infinite;}
.zf-sundisc{fill:#FBEBC0;opacity:.62;}
.zf-cloud ellipse{fill:url(#zgCloud);opacity:.9;}
.zf-cloud-1{animation:zCloud 86s linear infinite;}
.zf-cloud-2{animation:zCloud 112s linear infinite;animation-delay:-40s;}
.zf-cloud-3{animation:zCloud 138s linear infinite;animation-delay:-88s;}
.zf-cloud-4{animation:zCloud 170s linear infinite;animation-delay:-20s;opacity:.7;}
.zf-bird{fill:none;stroke:#7A7355;stroke-width:2.4;stroke-linecap:round;opacity:.42;}
.zf-birds-fly{animation:zBirdsFly 54s linear infinite;}
@keyframes zCloud{from{transform:translateX(-190px);}to{transform:translateX(1390px);}}
@keyframes zBirdsFly{from{transform:translate(-130px,26px);}to{transform:translate(1330px,-30px);}}
.zf-h1{fill:url(#zgH1);}
.zf-h2{fill:url(#zgH2);}
.zf-haze{fill:#F6EBD2;opacity:.42;}
.zf-mid{fill:url(#zgMid);}
.zf-near{fill:url(#zgNear);}
.zf-fore{fill:url(#zgFore);}

/* Depth and life added around the cows. */
.zf-mtn{fill:url(#zgMtn);opacity:.85;}
.zf-treeline ellipse{fill:#9DB081;}
.zf-trunk-far{fill:none;stroke:#8E8A66;stroke-width:3;}
.zf-path{fill:url(#zgPath);opacity:.75;}
.zf-tex{fill:url(#zgBlades);}
/* Sun rays: a slow turn and a slow pulse, too faint to compete with the text. */
.zf-rays polygon{fill:url(#zgRay);}
.zf-rays{transform-box:fill-box;transform-origin:50% 50%;opacity:.55;animation:zRays 140s linear infinite, zRayPulse 9s ease-in-out infinite;}
@keyframes zRays{to{transform:rotate(360deg);}}
@keyframes zRayPulse{0%,100%{opacity:.4;}50%{opacity:.7;}}
/* Birds beat their wings as they cross. */
.zf-bird{transform-box:fill-box;transform-origin:50% 60%;animation:zFlap .55s ease-in-out infinite alternate;}
.zf-bird-2{animation-duration:.48s;animation-delay:-.2s;}
.zf-bird-3{animation-duration:.62s;animation-delay:-.4s;}
@keyframes zFlap{from{transform:scaleY(1);}to{transform:scaleY(.35);}}
/* The big tree: trunk and canopy, the leaves swaying from the trunk. */
.zt-trunk{fill:#7A5A3A;}
.zt-branch{fill:none;stroke:#7A5A3A;stroke-width:7;stroke-linecap:round;}
.zt-canopy ellipse{fill:url(#zgCanopy);}
.zt-canopy{transform-box:fill-box;transform-origin:50% 100%;animation:zCanopy 8s ease-in-out infinite;}
@keyframes zCanopy{0%,100%{transform:rotate(0deg) skewX(0deg);}40%{transform:rotate(-1.1deg) skewX(-1.5deg);}70%{transform:rotate(.6deg) skewX(.8deg);}}
/* Wildflowers nodding with the grass. */
.zfl-y{fill:#F2C94C;}
.zfl-w{fill:#FFFDF5;}
.zfl-p{fill:#E99BB4;}
.zfl{transform-box:fill-box;transform-origin:50% 100%;}
.zfl-a{animation:zGrass 6.8s ease-in-out infinite;}
.zfl-b{animation:zGrass 8.6s ease-in-out infinite;animation-delay:-3.1s;}
/* Butterflies: a wandering flight, wings beating fast. */
.zbf-body{fill:#3B2F25;}
.zbf-w1{fill:#F2A93B;stroke:#B9741C;stroke-width:.8;}
.zbf-w2{fill:#FFF6DC;stroke:#C9B98A;stroke-width:.8;}
.zbf-wing{transform-box:fill-box;transform-origin:50% 50%;animation:zWing .22s ease-in-out infinite alternate;}
@keyframes zWing{from{transform:scaleX(1);}to{transform:scaleX(.25);}}
.zbf-1 .zbf-path{animation:zFly1 18s ease-in-out infinite;}
.zbf-2 .zbf-path{animation:zFly2 23s ease-in-out infinite;animation-delay:-7s;}
.zbf-2 .zbf-wing{animation-duration:.26s;}
@keyframes zFly1{
  0%{transform:translate(430px,300px);}20%{transform:translate(500px,262px);}
  40%{transform:translate(560px,288px);}60%{transform:translate(520px,246px);}
  80%{transform:translate(450px,272px);}100%{transform:translate(430px,300px);}
}
@keyframes zFly2{
  0%{transform:translate(880px,280px);}25%{transform:translate(960px,236px);}
  50%{transform:translate(1040px,270px);}75%{transform:translate(950px,300px);}
  100%{transform:translate(880px,280px);}
}
/* Pollen and dust lifting through the light. */
.zpl circle{fill:#FFF4CF;opacity:0;animation:zMote 9s ease-in-out infinite;}
.zpl circle:nth-child(2){animation-duration:11s;animation-delay:-2s;}
.zpl circle:nth-child(3){animation-duration:8s;animation-delay:-4s;}
.zpl circle:nth-child(4){animation-duration:12s;animation-delay:-6s;}
.zpl circle:nth-child(5){animation-duration:10s;animation-delay:-1s;}
.zpl circle:nth-child(6){animation-duration:9.5s;animation-delay:-5s;}
.zpl circle:nth-child(7){animation-duration:11.5s;animation-delay:-3s;}
.zpl circle:nth-child(8){animation-duration:8.5s;animation-delay:-7s;}
.zpl circle:nth-child(9){animation-duration:10.5s;animation-delay:-8s;}
@keyframes zMote{0%{opacity:0;transform:translate(0,0);}25%{opacity:.85;}75%{opacity:.5;}100%{opacity:0;transform:translate(26px,-70px);}}
@keyframes zSunBreathe{0%,100%{opacity:.75;}50%{opacity:1;}}
.zb-w{fill:none;stroke:#7A8A4A;stroke-width:2;stroke-linecap:round;opacity:.5;}
.zb-fly{animation:zBird 36s linear infinite;}

.zs-thatch{fill:url(#zgThatch);}
.zs-thatch2{fill:#B08D53;}
.zs-post{fill:#A9743E;}
.zs-rail{fill:none;stroke:#B98650;stroke-width:7;stroke-linecap:round;}

.zc-shadow{fill:#3E4A2E;opacity:.22;}
.zc-body{fill:url(#zgCow);stroke:#D8D2BE;stroke-width:1.6;}
.zc-shade{fill:#EAE4D2;opacity:.85;}
.zc-neck,.zc-face{fill:url(#zgCow);stroke:#D8D2BE;stroke-width:1.6;}
.zc-muzzle{fill:#F2C3CC;}
.zc-ear{fill:#F3B9C4;stroke:#E0A2AE;stroke-width:1.5;}
.zc-horn{fill:#3E332A;}
.zc-eye{fill:#3E332A;}
.zc-leg{fill:#F7F3E7;stroke:#D8D2BE;stroke-width:1.6;}
.zc-leg-far{fill:#E3DDCB;}
.zc-hoof{fill:#4A3D31;}
.zc-tailline{fill:none;stroke:#E8E2D0;stroke-width:6;stroke-linecap:round;}
.zc-tuft{fill:#4A3D31;}
.zc-udder{fill:#F3B9C4;stroke:#E09FAD;stroke-width:1.5;}
.zc-teat{fill:none;stroke:#EFAAB8;stroke-width:6;stroke-linecap:round;}

/* The cow pictures. One still image cannot move its head or tail the way
   the drawn cows did, so each one shifts its weight instead: a slow lean
   from the hooves and a breath, out of step with its neighbours so the herd
   never moves as one. */
.zc-pic{transform-box:fill-box;transform-origin:50% 92%;animation:zCowIdle 7s ease-in-out infinite;}
.zc-pic-a{animation-duration:8.4s;animation-delay:-3.1s;}
.zc-pic-b{animation-duration:6.6s;animation-delay:-1.2s;}
.zc-pic-c{animation-duration:7.8s;animation-delay:-4.6s;}
.zc-pic-d{animation-duration:9.2s;animation-delay:-2.2s;}
@keyframes zCowIdle{
  0%,100%{transform:rotate(0deg) scale(1,1);}
  30%{transform:rotate(-.8deg) scale(1.006,1.014);}
  60%{transform:rotate(.5deg) scale(1,1.004);}
}
.zc-tail{transform-box:fill-box;transform-origin:22% 0%;animation:zTail 3.8s ease-in-out infinite;}
.zc-tail-b{animation-duration:4.6s;animation-delay:-1.4s;}
.zc-tail-c{animation-duration:3.2s;animation-delay:-2.3s;}
.zc-tail-a{animation-duration:5.2s;animation-delay:-.7s;}
.zc-head{transform-box:fill-box;transform-origin:6% 40%;}
.zc-head-a{animation:zLook 9s ease-in-out infinite;}
.zc-head-b{animation:zGraze 6s ease-in-out infinite;}
.zc-head-c{animation:zGraze 7.2s ease-in-out infinite;animation-delay:-2.6s;}
.zc-head-d{animation:zLook 11s ease-in-out infinite;animation-delay:-4s;}

.zw-stool{fill:#A9743E;}
.zw-saree{fill:url(#zgSkirt);}
.zw-dupback{fill:#E0447A;opacity:.92;}
.zw-fold{fill:none;stroke:#D9A82B;stroke-width:2;stroke-linecap:round;}
.zw-bangle{fill:none;stroke:#D98F2E;stroke-width:2.4;stroke-linecap:round;}
.zw-border{fill:none;stroke:#D9932B;stroke-width:5;stroke-linecap:round;}
.zw-blouse{fill:#3B7EA8;}
.zw-skin{fill:#C98A5A;}
.zw-hair{fill:#241A14;}
.zw-drape{fill:url(#zgDup);}
.zw-arm{fill:none;stroke:#C98A5A;stroke-width:9;stroke-linecap:round;}
.zw-hand{fill:#C98A5A;}
.zw-arm-g{transform-box:fill-box;transform-origin:0% 0%;}
.zw-arm-1{animation:zArm1 1.7s ease-in-out infinite;}
.zw-arm-2{animation:zArm2 1.7s ease-in-out infinite;}
.zw-bucket{fill:#2E9E8F;stroke:#238577;stroke-width:2;}
.zw-bucket-rim{fill:none;stroke:#1F7368;stroke-width:4;stroke-linecap:round;}
.zw-milk{fill:#FFFDF8;}
.zw-squirt{fill:none;stroke:#FFFDF8;stroke-width:3.4;stroke-linecap:round;opacity:.95;animation:zSquirt 1.7s ease-in-out infinite;}
.zw-squirt-2{animation-delay:-.85s;}
.zw-pot{fill:#A9603A;}
.zw-potrim{fill:#8E4C2C;}

.zg path{fill:none;stroke:#4E663E;stroke-width:2.6;stroke-linecap:round;opacity:.75;}
.zg{transform-box:fill-box;transform-origin:50% 100%;}
.zg-a{animation:zGrass 6.4s ease-in-out infinite;}
.zg-b{animation:zGrass 8.2s ease-in-out infinite;animation-delay:-2.6s;stroke-opacity:.8;}

@keyframes zBird{from{transform:translate(-90px,14px);}to{transform:translate(1290px,-12px);}}
@keyframes zTail{0%,100%{transform:rotate(-7deg);}50%{transform:rotate(7deg);}}
@keyframes zGraze{0%,100%{transform:rotate(0deg);}45%{transform:rotate(4deg);}}
@keyframes zLook{0%,72%,100%{transform:rotate(0deg);}84%{transform:rotate(-3.5deg);}}
/* A squeeze, not a swing. At -3deg/+4deg the hands travelled about twelve
   units vertically while the teats they are meant to be holding are barely
   five long, so for most of the cycle they were off the cow entirely. The
   arms are long, so a small angle is a large movement at the hand: +-1.5deg
   keeps the fists on the teats the whole way round and still reads as
   pulling. */
@keyframes zArm1{0%,100%{transform:rotate(-1deg);}50%{transform:rotate(1.5deg);}}
@keyframes zArm2{0%,100%{transform:rotate(1.5deg);}50%{transform:rotate(-1deg);}}
@keyframes zSquirt{0%{opacity:0;}20%{opacity:.95;}70%{opacity:.35;}100%{opacity:0;}}
@keyframes zGrass{0%,100%{transform:skewX(-4deg);}50%{transform:skewX(4deg);}}

/* membership banner */
.membership-banner{
  max-width:980px;margin:0 auto 1.7rem;position:relative;overflow:hidden;
  border-radius:var(--radius);box-shadow:var(--shadow);border:1px solid var(--border);background:var(--cream-alt);
}
.membership-banner img{
  width:100%;height:clamp(150px,18vw,205px);object-fit:cover;display:block;
  /* The photograph is a tall portrait and this is a wide strip, so cover shows
     only a narrow horizontal band of it - 16% of the source height on a
     desktop. Dead centre put the top of that band on the wall behind the
     herd; 55% drops it onto the animals and leaves ground along the bottom,
     which is also what the caption gradient needs to sit over. */
  object-position:50% 55%;
  transition:transform .8s cubic-bezier(.2,.7,.3,1);
}
.membership-banner:hover img{transform:scale(1.05);}
.membership-banner figcaption{
  position:absolute;left:0;right:0;bottom:0;padding:2.2rem 1.5rem 1.1rem;
  background:linear-gradient(180deg,transparent,rgba(36,56,45,.88));
  color:var(--cream);font-size:.92rem;font-weight:600;text-align:left;
}
.hero::before,.hero::after{
  content:"";position:absolute;width:60vmax;height:60vmax;border-radius:50%;
  filter:blur(70px);opacity:.16;z-index:0;pointer-events:none;
}
.hero::before{background:var(--gold);top:-25%;left:-15%;animation:heroDrift1 20s ease-in-out infinite alternate;z-index:0;}
.hero::after{background:var(--green);bottom:-30%;right:-15%;animation:heroDrift2 24s ease-in-out infinite alternate;}
@keyframes heroDrift1{from{transform:translate(0,0) scale(1);}to{transform:translate(5%,6%) scale(1.08);}}
@keyframes heroDrift2{from{transform:translate(0,0) scale(1);}to{transform:translate(-6%,-5%) scale(1.05);}}
.hero-inner{max-width:760px;margin:0 auto;position:relative;z-index:3;}
.eyebrow{
  display:inline-flex;align-items:center;gap:.5em;
  background:var(--card-bg);border:1px solid var(--border);color:var(--gold-deep);
  padding:.5em 1.1em;border-radius:999px;font-size:.82rem;font-weight:700;letter-spacing:.03em;
  box-shadow:var(--shadow);margin-bottom:1.6rem;
}
.eyebrow svg{width:15px;height:15px;}
.hero h1{font-size:clamp(2.1rem,4.9vw,3.3rem);margin-bottom:.42em;}
.hero-lede{font-size:1.08rem;max-width:600px;margin:0 auto 1.5rem;}
.hero-actions{display:flex;gap:1rem;justify-content:center;flex-wrap:wrap;margin-bottom:1.2rem;}
.hero-note{font-size:.85rem;color:var(--ink-soft);opacity:.8;}

/* stats */
.stats{padding:0 1.5rem 2.4rem;}
.stats-grid{
  max-width:1000px;margin:0 auto;display:grid;grid-template-columns:repeat(2,1fr);gap:1rem;
}
.stat{
  background:var(--card-bg);border:1px solid var(--border);border-radius:var(--radius);
  padding:1.8rem 1rem;text-align:center;box-shadow:var(--shadow);
}
.stat-value{display:block;font-family:var(--font-display);font-size:2.4rem;color:var(--green);}
.stat-word .stat-value{color:var(--gold-deep);}
.stat-label{display:block;margin-top:.3em;font-size:.82rem;text-transform:uppercase;letter-spacing:.08em;color:var(--ink-soft);font-weight:600;}

/* story */
.story{padding:2.7rem 1.5rem;background:var(--card-bg);border-top:1px solid var(--border);}
.story-inner{max-width:980px;margin:0 auto;display:grid;grid-template-columns:1.1fr .9fr;gap:3rem;align-items:center;}
.story-text h2{font-size:2rem;}
.story-quote{
  background:var(--card-bg);color:var(--ink);border-radius:var(--radius);padding:2.4rem;position:relative;
  border:1px solid var(--border);border-left:3px solid var(--gold);box-shadow:var(--shadow);
}
.story-quote .quote-mark{width:32px;height:32px;color:var(--gold);opacity:.9;margin-bottom:.6rem;}
.story-quote p{color:var(--ink);font-family:var(--font-display);font-size:1.25rem;font-style:italic;margin-bottom:1rem;}
.story-quote cite{color:var(--green-deep);font-style:normal;font-size:.9rem;}

/* benefits */
.benefits{padding:2.7rem 1.5rem;background:var(--cream-alt);}
.benefit-grid{
  max-width:1060px;margin:0 auto;display:grid;grid-template-columns:repeat(3,1fr);gap:.85rem;
  /* Every card the same height, so one flipping does not leave the row
     ragged - and so each card is already tall enough for whichever of its
     two faces is longer. align-items:start was right for an accordion that
     pushed the card open; a flip needs the space reserved up front. */
  grid-auto-rows:1fr;
}
.benefit-card{
  text-align:left;background:var(--card-bg);border:1px solid var(--border);border-radius:var(--radius);
  padding:1.15rem;cursor:pointer;font-family:var(--font-body);color:var(--ink);
  transition:box-shadow .2s ease, transform .2s ease, border-color .2s ease;
  /* The depth the rotation is seen through. On the card rather than the grid
     so each one flips about its own centre; on the grid, cards at the edges
     would swing through a shared vanishing point and look skewed. */
  perspective:900px;
}
.benefit-card:hover{box-shadow:var(--shadow);transform:translateY(-3px);border-color:rgba(191,143,58,.45);border-color:color-mix(in srgb, var(--gold) 40%, var(--border));}
.benefit-top{display:flex;align-items:center;justify-content:space-between;color:var(--gold-deep);}
.benefit-top svg{width:24px;height:24px;}
.benefit-num{font-family:var(--font-display);font-size:.85rem;color:var(--ink-soft);}
/* No chevron. It pointed down because the card used to open downwards; on a
   card that turns over it promised the wrong movement. The padding-right it
   needed goes with it, so the titles now use the full width. */
.benefit-title{font-weight:600;font-size:1.02rem;}
/* ===== the flip =====

   Both faces sit in the SAME grid cell, which is what lets the card size
   itself to whichever of the two is taller. The alternative is a fixed
   height, and a fixed height is a number that is wrong the first time
   somebody edits a description.

   Absolute positioning would do the same stacking but takes both faces out
   of flow, so the card would collapse to nothing and need that height after
   all. grid-area on both children keeps them measured. */
.benefit-flip{
  display:grid;
  min-height:100%;
  transform-style:preserve-3d;
  -webkit-transform-style:preserve-3d;
  transition:transform .55s cubic-bezier(.2,.75,.3,1);
}
.benefit-face{
  grid-area:1/1;
  display:flex;flex-direction:column;gap:.45rem;
  /* Without this the reversed face shows through as mirror writing. The
     -webkit- line is for older iOS, which needs it and is the reason the
     unprefixed one alone is not enough here. */
  backface-visibility:hidden;
  -webkit-backface-visibility:hidden;
}
/* Pre-rotated, so the parent turning 180deg brings it to face the reader. */
.benefit-back{
  transform:rotateY(180deg);
  justify-content:center;
}
.benefit-card[aria-expanded="true"] .benefit-flip{transform:rotateY(180deg);}

.benefit-desc-in{font-size:.92rem;line-height:1.5;color:var(--ink-soft);}

/* A card mid-turn should not also be lifting towards the reader. */
.benefit-card[aria-expanded="true"]{transform:none;}

/* ===== without the rotation =====

   prefers-reduced-motion means no 3D turn at all - not a slower one. The two
   faces swap outright, which is the same disclosure without the movement.
   visibility rather than display so the grid cell keeps its size and the card
   does not resize as it changes. */
@media (prefers-reduced-motion: reduce){
  .benefit-flip{transition:none;}
  .benefit-card[aria-expanded="true"] .benefit-flip{transform:none;}
  .benefit-back{transform:none;visibility:hidden;}
  .benefit-card[aria-expanded="true"] .benefit-front{visibility:hidden;}
  .benefit-card[aria-expanded="true"] .benefit-back{visibility:visible;}
}

/* herd */
.herd{padding:2.7rem 1.5rem;background:var(--green-tint);border-top:1px solid var(--border);}
.herd-grid{max-width:980px;margin:0 auto;display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:1.5rem;text-align:center;}
/* 2x2 grid quadrant cropping */
.cell{display:block;position:absolute;overflow:hidden;}
.cell img{position:absolute;width:204%;height:204%;object-fit:fill;max-width:none;}
.cell-tl img{left:0;top:0;transform-origin:25% 25%;}
.cell-tr img{left:-104%;top:0;transform-origin:75% 25%;}
.cell-bl img{left:0;top:-104%;transform-origin:25% 75%;}
.cell-br img{left:-104%;top:-104%;transform-origin:75% 75%;}

/* A cow with her OWN photograph rather than a quadrant of the shared one.
 *
 * Everything above scales the image to 204% and slides it so one quarter
 * shows; this undoes all of it so the whole frame is used. Declared after
 * those rules on purpose - `.cell img` and `.cell-full img` have identical
 * specificity, so order is what decides.
 *
 * --focus says where the animal's HEAD is, as a percentage across the
 * photograph, and each card sets its own. It belongs to the picture rather
 * than to the layout: these are 4:3 landscapes going into a 3:4 portrait, so
 * cover keeps the full height and crops 44% of the width, and where that cut
 * falls decides whether a face survives it. Centred cut through Lata's muzzle
 * and removed Gauri's head almost entirely - they need 20% and 70%.
 *
 * A custom property rather than a class per cow, so the next photograph
 * brings its own number and needs no new rule. 50% if none is given.
 *
 * Note the avatar crops this a SECOND time - a circle when closed, a 5:4
 * window when open - so the visible area is never the 3:4 crop itself. Worth
 * rendering both before trusting a value. */
.cell-full img{
  position:absolute;left:0;top:0;width:100%;height:100%;
  object-fit:cover;object-position:var(--focus,50%) 50%;
}

/* Cards. Opening a cow happens IN the layout: its column widens, the round
   photo grows into a large soft-square one, the details appear beneath, and
   the other three narrow beside it. Nothing floats over the page, so nothing
   is ever covered - the section simply grows and the content below moves
   down with it. The script animates the change with GSAP Flip; everything
   here is the resting state at either end, so without the script's animation
   it still opens and closes, just instantly. */
.herd-grid{align-items:start;transition:none;}
.herd-card{position:relative;outline:none;cursor:pointer;-webkit-tap-highlight-color:transparent;}
/* What the Flip animation moves. The card itself carries the scroll reveal,
   whose animation holds `transform`, so it cannot be animated directly. */
.herd-body{display:flex;flex-direction:column;align-items:center;}
.herd-avatar{
  width:94px;aspect-ratio:1;border-radius:50%;margin:0 auto .7rem;flex-shrink:0;
  position:relative;overflow:hidden;background:var(--cream-alt);
  box-shadow:0 10px 20px rgba(58,52,44,.12);
  transition:box-shadow .3s ease;
}
.herd-avatar .cell{left:50%;top:50%;transform:translate(-50%,-50%);width:100%;aspect-ratio:3/4;}
.herd-card:hover .herd-avatar{box-shadow:0 14px 26px rgba(58,52,44,.22);}
.herd-card:focus-visible .herd-avatar{outline:2px solid var(--gold);outline-offset:4px;}
.herd-card h3{margin-bottom:.2em;font-size:1.1rem;}
.herd-card p{font-size:.9rem;}
.herd-more{display:none;width:100%;text-align:left;}
.herd-facts{display:flex;flex-wrap:wrap;gap:.4rem;margin:0;padding:.7rem 0 0;list-style:none;}
.herd-facts li{
  padding:.25em .75em;border-radius:999px;font-size:.72rem;color:var(--green-deep);
  border:1px solid var(--border);background:var(--card-bg);
}

/* Open. The widened column comes from the grid, one rule per position. */
.herd-grid[data-open="0"]{grid-template-columns:minmax(0,2.4fr) repeat(3,minmax(0,1fr));}
.herd-grid[data-open="1"]{grid-template-columns:minmax(0,1fr) minmax(0,2.4fr) repeat(2,minmax(0,1fr));}
.herd-grid[data-open="2"]{grid-template-columns:repeat(2,minmax(0,1fr)) minmax(0,2.4fr) minmax(0,1fr);}
.herd-grid[data-open="3"]{grid-template-columns:repeat(3,minmax(0,1fr)) minmax(0,2.4fr);}
.herd-card.is-open{cursor:default;}
.herd-card.is-open .herd-body{align-items:flex-start;text-align:left;}
.herd-card.is-open .herd-avatar{
  width:100%;aspect-ratio:5/4;border-radius:24px;margin:0 0 1rem;
  box-shadow:0 22px 44px rgba(36,56,45,.24);
}
/* An opened card shows its photograph at the card's own shape.
 *
 * The cell is 3:4 so the closed circle has something to crop from. Left at
 * 3:4 inside a 5:4 window it gets cropped a SECOND time, discarding the top
 * and bottom of the picture at exactly the moment it is meant to be looked
 * at - which is why Gauri lost the top of her hump and sat off-centre once
 * opened.
 *
 * Matching the two shapes means cover crops once, from a 4:3 photograph into
 * a 5:4 box: a few percent off the sides and nothing off the top. The animal
 * ends up centred and whole without --focus having to rescue her.
 *
 * Only .cell-full. The sprite quadrants measure their 204% offsets against a
 * 3:4 cell and come apart if it changes. */
.herd-card.is-open .cell-full{aspect-ratio:5/4;}
.herd-card.is-open h3{font-size:1.5rem;margin-bottom:.35rem;}
.herd-card.is-open .herd-more{display:block;}
/* The others step back a little so the open one leads. */
.herd-grid[data-open] .herd-card:not(.is-open) .herd-body{opacity:.72;transition:opacity .4s ease;}
.herd-grid[data-open] .herd-card:not(.is-open):hover .herd-body{opacity:1;}

/* Two columns: there is no room to widen a column, so the open cow takes the
   whole row and the others flow around it. */
@media (max-width:900px){
  .herd-grid[data-open]{grid-template-columns:repeat(2,minmax(0,1fr));}
  .herd-card.is-open{grid-column:1 / -1;}
  .herd-card.is-open .herd-avatar{aspect-ratio:4/3;}
  /* The cell follows the avatar here too, or the second crop comes back on
     exactly the narrow screens where the card is largest relative to it. */
  .herd-card.is-open .cell-full{aspect-ratio:4/3;}
}

/* gallery */
.gallery{padding:2.7rem 1.5rem;background:var(--card-bg);border-top:1px solid var(--border);}
.gallery-grid{
  max-width:980px;margin:0 auto;display:grid;grid-template-columns:repeat(2,1fr);gap:1.2rem;
}
.gallery-item{
  margin:0;position:relative;overflow:hidden;border-radius:var(--radius);
  box-shadow:var(--shadow);border:1px solid var(--border);background:var(--cream-alt);
}
.gallery-item.reveal{opacity:1;transform:none;clip-path:inset(0 100% 0 0);}
/* Finished state declared here too - a gallery photograph hidden behind an
   unplayed wipe is as blank as a hidden section. */
.gallery-item.reveal.in-view{clip-path:inset(0 0 0 0);animation:galleryWipe .9s cubic-bezier(.65,0,.35,1) forwards;}
.gallery-grid .gallery-item:nth-child(2){animation-delay:.08s;}
.gallery-grid .gallery-item:nth-child(3){animation-delay:.16s;}
.gallery-grid .gallery-item:nth-child(4){animation-delay:.24s;}
@keyframes galleryWipe{from{clip-path:inset(0 100% 0 0);}to{clip-path:inset(0 0 0 0);}}
.gallery-item img{
  width:100%;height:185px;object-fit:cover;display:block;
  transition:transform .6s cubic-bezier(.2,.7,.3,1);
}
.gallery-item:hover img{transform:scale(1.07);}
.gallery-item figcaption{
  position:absolute;left:0;right:0;bottom:0;padding:1.6rem 1.2rem .95rem;
  background:linear-gradient(180deg, transparent, rgba(36,56,45,.88));
  color:var(--cream);font-size:.88rem;font-weight:600;letter-spacing:.01em;text-align:left;
  transform:translateY(6px);opacity:.94;transition:transform .35s ease, opacity .35s ease;
}
.gallery-item:hover figcaption{transform:translateY(0);opacity:1;}
/* The 01 - 04 counter only means something while the photos slide. */
.gallery-count{display:none;}

/* Sliding gallery, as in the design preview: the section is made tall, its
   contents pin under the header, and the vertical scroll through that height
   moves the row of photos sideways (the script sets the height and the
   transform). Each photo also drifts a little inside its frame (--ix), which
   is what makes the row feel like it is passing the camera rather than
   being dragged. Only on a wide screen with motion allowed - the script adds
   .gallery-slide, so without it this is all inert. */
.gallery.gallery-slide{height:var(--gh,auto);padding:0;}
.gallery-slide .gallery-pin{
  position:sticky;top:0;height:100vh;overflow:hidden;
  display:flex;align-items:center;gap:3rem;padding:90px 0 40px;
}
.gallery-slide .section-head{flex:0 0 min(360px,30vw);margin:0 0 0 max(1.5rem,calc((100vw - 1060px)/2));text-align:left;}
.gallery-slide .section-sub{margin-left:0;}
.gallery-slide .gallery-count{display:flex;align-items:center;gap:.8rem;margin-top:1.6rem;font-size:.82rem;letter-spacing:.08em;color:var(--gold-deep);}
.gallery-slide .gallery-count i{display:block;width:110px;height:1px;background:var(--border);position:relative;}
.gallery-slide .gallery-count i::after{
  content:"";position:absolute;inset:0;background:var(--gold);
  transform-origin:0 50%;transform:scaleX(var(--gp,0));
}
.gallery-slide .gallery-grid{
  display:flex;align-items:flex-start;gap:1.75rem;max-width:none;margin:0;
  padding-right:max(1.5rem,calc((100vw - 1060px)/2));will-change:translate;
}
.gallery-slide .gallery-item{flex:0 0 auto;width:min(36vw,420px);}
/* Every other photo sits lower, so the row reads as a strip of prints. */
.gallery-slide .gallery-item:nth-child(even){margin-top:60px;}
.gallery-slide .gallery-item img{
  height:min(56vh,480px);transform:translateX(var(--ix,0px)) scale(1.15);
  transition:none;
}
.gallery-slide .gallery-item:hover img{transform:translateX(var(--ix,0px)) scale(1.2);transition:transform .6s cubic-bezier(.2,.7,.3,1);}

/* process */
.process{padding:2.7rem 1.5rem;background:var(--card-bg);position:relative;overflow:hidden;}
.process > .section-head,.process > .ritual{position:relative;z-index:1;}

/* ambient process background */
.process-bg{position:absolute;top:0;right:0;bottom:0;left:0;z-index:0;pointer-events:none;overflow:hidden;}
.pbg-blob{position:absolute;border-radius:50%;filter:blur(58px);}
.pbg-b1{
  width:44vmax;height:44vmax;background:var(--gold);opacity:.25;
  top:-16%;left:-14%;animation:pbgDrift1 26s ease-in-out infinite alternate;
}
.pbg-b2{
  width:36vmax;height:36vmax;background:var(--green);opacity:.20;
  bottom:-20%;right:-12%;animation:pbgDrift2 33s ease-in-out infinite alternate;
}
.pbg-b3{
  width:26vmax;height:26vmax;background:#E9BE55;opacity:.26;
  top:34%;left:54%;animation:pbgDrift3 21s ease-in-out infinite alternate;
}
/* churning vortex */
.pbg-svg{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;display:block;}
.pbg-swirl{
  fill:none;stroke:var(--gold);stroke-linecap:round;
  transform-box:fill-box;transform-origin:50% 50%;
}
.pbg-s1{stroke-width:2.6;stroke-dasharray:210 340;opacity:.30;animation:pbgChurnA 6.5s ease-in-out infinite;}
.pbg-s2{stroke-width:2.2;stroke-dasharray:300 560;opacity:.24;animation:pbgChurnB 8s ease-in-out infinite;}
.pbg-s3{stroke-width:2;stroke-dasharray:380 900;opacity:.19;animation:pbgChurnA 10s ease-in-out infinite;animation-delay:-2.5s;}
.pbg-s4{stroke-width:1.6;stroke-dasharray:460 1300;opacity:.14;animation:pbgChurnB 12.5s ease-in-out infinite;animation-delay:-4s;}

/* makkhan granules rising */
.pbg-gran{
  position:absolute;border-radius:50%;background:#FFF4D6;
  box-shadow:0 0 12px rgba(255,235,180,.95);opacity:0;
  animation:pbgFloat linear infinite;
}
.pbg-g1{width:10px;height:10px;left:18%;bottom:16%;animation-duration:13s;animation-delay:-1s;}
.pbg-g2{width:7px;height:7px;left:31%;bottom:9%;animation-duration:17s;animation-delay:-6s;}
.pbg-g3{width:12px;height:12px;left:47%;bottom:20%;animation-duration:15s;animation-delay:-10s;}
.pbg-g4{width:8px;height:8px;left:62%;bottom:12%;animation-duration:19s;animation-delay:-3s;}
.pbg-g5{width:11px;height:11px;left:76%;bottom:22%;animation-duration:14s;animation-delay:-8s;}
.pbg-g6{width:6px;height:6px;left:88%;bottom:14%;animation-duration:21s;animation-delay:-13s;}

/* milk droplets falling */
.pbg-drop{
  position:absolute;width:9px;height:14px;
  border-radius:52% 52% 60% 60%;background:rgba(255,253,248,.95);
  box-shadow:0 0 10px rgba(255,255,255,.8);opacity:0;
  animation:pbgDrop linear infinite;
}
.pbg-d1{left:24%;top:6%;animation-duration:6.5s;animation-delay:-1.5s;}
.pbg-d2{left:55%;top:3%;animation-duration:8s;animation-delay:-4.5s;}
.pbg-d3{left:81%;top:8%;animation-duration:7.2s;animation-delay:-6.5s;}
.pbg-wisp{
  position:absolute;bottom:-14%;border-radius:50%;
  width:clamp(56px,8vw,120px);height:54%;
  background:linear-gradient(180deg, rgba(255,244,214,0), rgba(255,228,168,.92));
  filter:blur(24px);opacity:0;
  animation:pbgRise linear infinite;
}
.pbg-w1{left:12%;animation-duration:17s;animation-delay:-2s;}
.pbg-w2{left:34%;animation-duration:22s;animation-delay:-9s;width:clamp(40px,6vw,88px);}
.pbg-w3{left:63%;animation-duration:19s;animation-delay:-14s;}
.pbg-w4{left:83%;animation-duration:25s;animation-delay:-5s;width:clamp(36px,5vw,76px);}

@media (max-width:720px){
  .pbg-b3,.pbg-w2,.pbg-w4,.pbg-g4,.pbg-g6,.pbg-d3{display:none;}
  .pbg-s4{display:none;}
  .pbg-blob{filter:blur(46px);}
  .pbg-wisp{filter:blur(20px);}
}

@keyframes pbgDrift1{from{transform:translate(0,0) scale(1);}to{transform:translate(7%,6%) scale(1.1);}}
@keyframes pbgDrift2{from{transform:translate(0,0) scale(1);}to{transform:translate(-6%,-7%) scale(1.08);}}
@keyframes pbgDrift3{from{transform:translate(0,0) scale(1);}to{transform:translate(-9%,7%) scale(1.14);}}
@keyframes pbgChurnA{0%,100%{transform:rotate(-22deg);}50%{transform:rotate(22deg);}}
@keyframes pbgChurnB{0%,100%{transform:rotate(19deg);}50%{transform:rotate(-19deg);}}
}
}
}
@keyframes pbgFloat{
  0%{opacity:0;transform:translate(0,0) scale(.6);}
  14%{opacity:.62;}
  70%{opacity:.38;}
  100%{opacity:0;transform:translate(30px,-190px) scale(1);}
}
@keyframes pbgDrop{
  0%{opacity:0;transform:translateY(-10px) scaleY(.8);}
  16%{opacity:.68;}
  80%{opacity:.44;}
  100%{opacity:0;transform:translateY(230px) scaleY(1.35);}
}
@keyframes pbgRise{
  0%{opacity:0;transform:translateY(0) scaleX(1);}
  14%{opacity:.54;}
  68%{opacity:.3;}
  100%{opacity:0;transform:translateY(-118%) scaleX(1.45);}
}
.ritual{max-width:640px;margin:0 auto;position:relative;padding-left:2.6rem;}
.ritual-line{
  position:absolute;left:20px;top:8px;bottom:8px;width:2px;background:var(--border);
}
.ritual-line-fill{
  position:absolute;left:0;top:0;width:100%;height:0%;background:var(--gold);
  transition:height .1s linear;
}
.ritual-steps{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:1.85rem;}
.ritual-step{position:relative;}
.ritual-icon{
  position:absolute;left:-2.6rem;top:0;width:42px;height:42px;border-radius:50%;
  background:var(--card-bg);border:2px solid var(--border);display:flex;align-items:center;justify-content:center;
  color:var(--ink-soft);transition:all .3s ease;
}
.ritual-icon svg{width:20px;height:20px;}
.ritual-step.active .ritual-icon{border-color:var(--gold);color:var(--gold-deep);background:#F7EEDC;background:color-mix(in srgb, var(--gold) 12%, var(--card-bg));box-shadow:0 6px 16px rgba(191,143,58,.2);}
.ritual-tag{display:block;font-size:.78rem;text-transform:uppercase;letter-spacing:.1em;color:var(--gold-deep);font-weight:700;margin-bottom:.3em;}
.ritual-step h3{font-size:1.3rem;margin-bottom:.3em;}
.ritual-step p{margin:0;}

/* shop */
.shop{padding:2.7rem 1.5rem;background:var(--card-bg);border-top:1px solid var(--border);}
.shop-grid{max-width:1060px;margin:0 auto;display:grid;grid-template-columns:repeat(3,1fr);gap:1.2rem;}
/* Two products: keep the cards at their three-column width, centred. */
.shop-grid-pair{max-width:710px;grid-template-columns:repeat(2,1fr);}
.shop-card{
  background:var(--card-bg);border:1px solid var(--border);border-radius:var(--radius);padding:1.2rem;
  position:relative;box-shadow:var(--shadow);transition:transform .25s ease, box-shadow .25s ease;
  /* A column, so .shop-actions can sit on the bottom edge. Descriptions wrap to
     different lengths, and without this the cards' buttons land at different heights. */
  display:flex;flex-direction:column;
}
.shop-card:hover{transform:translateY(-4px);box-shadow:0 16px 32px rgba(59,45,30,.14);}
.shop-card-featured{border-color:var(--gold);}
.shop-badge{
  position:absolute;top:-11px;right:1.2rem;background:var(--gold);color:#fff;font-size:.72rem;font-weight:700;
  padding:.3em .8em;border-radius:999px;letter-spacing:.03em;
}
.shop-media{
  position:relative;width:100%;aspect-ratio:3/2;overflow:hidden;
  border-radius:14px;margin-bottom:.85rem;background:var(--cream-alt);
}
.shop-media .cell{top:0;right:0;bottom:0;left:0;width:100%;height:100%;}
.shop-media img{transition:transform .6s cubic-bezier(.2,.7,.3,1);}
.shop-card:hover .shop-media img{transform:scale(1.07);}
.shop-media-icon{display:flex;align-items:center;justify-content:center;background:linear-gradient(150deg,#F3E4C4,#E0C68F);}
.shop-media-icon svg{width:46px;height:46px;color:var(--gold-deep);}
.shop-card h3{font-size:1.08rem;margin-bottom:.3em;}
.shop-card p{font-size:.9rem;margin-bottom:1rem;}
/* The "100% A2" line under each jar's name: a label, not a sentence. */
.shop-card .shop-a2{
  margin:-.1em 0 .5em;font-size:.72rem;font-weight:700;letter-spacing:.07em;
  text-transform:uppercase;color:var(--gold-deep);
}
.price{font-family:var(--font-display);font-size:1.3rem;color:var(--green);}
.price em{display:block;font-style:normal;font-size:.68rem;text-transform:uppercase;letter-spacing:.08em;color:var(--ink-soft);margin-top:.15em;}

/* ===== the two prices =====

   Every card ships both, and CSS decides which one is the headline. Done
   this way rather than by rewriting the cards in JS so that the price is
   never blank while /api/me is in flight, and so the page still shows a
   correct, complete price if that request never comes back at all.

   The guest price is the default for the same reason the database column is:
   if the member state never arrives, the visitor sees - and is charged - the
   regular price. The failure is a missing discount, which someone will tell
   us about, rather than a free one, which nobody ever will. */
.price-member,.price-hint-member{display:none;}
.price-hint-guest{color:var(--gold-deep);}

body.zv-member .price-regular,body.zv-member .price-hint-guest{display:none;}
body.zv-member .price-member{display:inline;}
body.zv-member .price-hint-member{display:block;text-decoration:line-through;}

/* reviews */
.reviews{padding:2.7rem 1.5rem;background:var(--cream-alt);}
.carousel{max-width:680px;margin:0 auto;}
.carousel-track{position:relative;min-height:220px;}
.review-card{
  margin:0;background:var(--card-bg);border:1px solid var(--border);border-radius:var(--radius);
  padding:2.2rem;box-shadow:var(--shadow);
  position:absolute;top:0;right:0;bottom:0;left:0;opacity:0;pointer-events:none;transform:translateY(8px);
  transition:opacity .3s ease, transform .3s ease;
}
.review-card.active{opacity:1;pointer-events:auto;transform:translateY(0);position:relative;}
.review-card .quote-mark{width:26px;height:26px;color:var(--gold);margin-bottom:.6rem;}
.review-card p{font-family:var(--font-display);font-style:italic;font-size:1.1rem;color:var(--ink);}
.review-card footer{display:flex;align-items:center;gap:.7em;font-size:.88rem;color:var(--ink-soft);}
.avatar{
  width:38px;height:38px;border-radius:50%;background:var(--green);color:#fff;display:flex;
  align-items:center;justify-content:center;font-weight:700;flex-shrink:0;
}
.carousel-controls{display:flex;align-items:center;justify-content:center;gap:1rem;margin-top:1.4rem;}
.carousel-btn{
  width:40px;height:40px;border-radius:50%;border:1px solid var(--border);background:var(--card-bg);
  display:flex;align-items:center;justify-content:center;cursor:pointer;color:var(--ink);
}
.carousel-btn:hover{border-color:var(--gold);color:var(--gold-deep);}
.carousel-btn svg{width:18px;height:18px;}
.carousel-dots{display:flex;gap:.5em;}
.carousel-dots button{
  width:8px;height:8px;border-radius:50%;background:var(--border);border:none;cursor:pointer;padding:0;
}
.carousel-dots button.active{background:var(--gold);width:22px;border-radius:4px;transition:width .2s ease;}

/* pricing */
.pricing{padding:2.7rem 1.5rem;background:var(--maroon);color:var(--cream);border-top:none;}
.pricing-inner{max-width:980px;margin:0 auto;display:grid;grid-template-columns:1fr 1fr;gap:3rem;align-items:center;}
.pricing-text h2{color:var(--cream);font-size:2rem;}
.pricing-text p{color:rgba(251,246,236,.78);}
.pricing-text .section-kicker{color:var(--gold);}
.mini-quote{
  border-left:3px solid var(--gold);padding-left:1rem;margin:1.5rem 0 0;
  font-family:var(--font-display);font-style:italic;color:var(--cream);
}
.pricing-card{
  background:var(--card-bg);color:var(--ink);border-radius:var(--radius);padding:2rem;border:1px solid var(--border);box-shadow:var(--shadow);
}
.pricing-card-head{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:.8rem;margin-bottom:1.2rem;font-weight:600;}
.rate-toggle{display:flex;background:rgba(43,38,32,0.06);border-radius:999px;padding:3px;gap:2px;}
.rate-btn{
  border:none;background:transparent;padding:.4em 1em;border-radius:999px;font-size:.82rem;font-weight:700;
  cursor:pointer;color:var(--ink-soft);
}
.rate-btn.active{background:var(--gold);color:#fff;}
.pricing-row{display:flex;justify-content:space-between;align-items:center;padding:.85rem 0;border-bottom:1px solid var(--border);font-size:.98rem;}
.pricing-row strong{font-family:var(--font-display);font-size:1.15rem;}
.savings-row .savings-highlight{color:var(--gold-deep);}
.pricing-fine{font-size:.82rem;margin:1rem 0 1.2rem;}
.pricing-cap{display:flex;align-items:center;gap:.5em;justify-content:center;font-size:.85rem;color:var(--ink-soft);margin:1rem 0 0;}
.pricing-cap svg{width:16px;height:16px;}

/* instagram */

/* join */
.join{padding:2.7rem 1.5rem;background:var(--cream-alt);border-top:1px solid var(--border);}
.join-inner{max-width:980px;margin:0 auto;display:grid;grid-template-columns:1fr 1fr;gap:3rem;align-items:start;}
/* A grid item defaults to min-width:auto, which means it refuses to shrink
   below its content's minimum - and the form's minimum is the width of an
   <input> plus 2rem of padding each side. On a 320px phone that pushed the
   column about 8px wider than the screen. min-width:0 lets it shrink; the
   inputs then stretch to whatever is left. */
.join-inner > *,.pricing-inner > *,.story-inner > *{min-width:0;}
.join-text h2{font-size:2rem;}
.join-list{list-style:none;margin:1.5rem 0 0;padding:0;display:flex;flex-direction:column;gap:.8rem;}
.join-list li{display:flex;align-items:center;gap:.6em;font-weight:500;color:var(--ink);}
.join-list svg{width:18px;height:18px;color:var(--green);flex-shrink:0;}
.form-alert{
  display:block;margin:.9rem 0 0;padding:.8em 1em;
  background:rgba(192,57,43,.08);border:1px solid rgba(192,57,43,.3);
  border-radius:10px;color:#8f2d22;font-size:.86rem;font-weight:500;line-height:1.5;
}
.join-done{
  background:var(--card-bg);border:1px solid var(--border);border-radius:var(--radius);
  padding:2.6rem 2rem;box-shadow:var(--shadow);text-align:center;
}
.join-done h4{font-size:1.35rem;margin:0 0 .55em;}
.join-done p{margin:0 0 .55em;}
.join-done-sub{font-size:.85rem;color:var(--ink-soft);word-break:break-word;}
.btn[disabled]{opacity:.6;cursor:not-allowed;transform:none !important;box-shadow:none;}
.join-form{
  background:var(--card-bg);border:1px solid var(--border);border-radius:var(--radius);padding:2rem;box-shadow:var(--shadow);
}
.form-row{margin-bottom:1.1rem;display:flex;flex-direction:column;gap:.4rem;}
.form-row label{font-size:.85rem;font-weight:700;color:var(--ink);}
.form-row input{
  padding:.8em 1em;border-radius:10px;border:1px solid var(--border);background:rgba(43,38,32,0.03);color:var(--ink);
  font-size:.95rem;font-family:var(--font-body);
}
.form-row input:focus{outline:2px solid var(--gold);outline-offset:1px;}
.form-row.invalid input{border-color:#c0392b;}
/* The State dropdown, matched to the text fields beside it.

   Without this it is the only control in checkout wearing the operating
   system's own look - different height, different font, square corners, grey
   fill - sitting directly under City and PIN code, which made it read as
   broken rather than as a dropdown.

   appearance:none strips the native control, so the arrow has to be drawn
   back on: an inline SVG as a background image, padded clear on the right so
   a long state name never runs underneath it. */
.form-row select{
  padding:.8em 2.4em .8em 1em;border-radius:10px;border:1px solid var(--border);
  background-color:rgba(43,38,32,0.03);color:var(--ink);
  /* line-height is left at normal, the same as the inputs. Pinning it to a
     number here made the dropdown 3px shorter than City and PIN beside it. */
  font-size:.95rem;font-family:var(--font-body);
  width:100%;appearance:none;-webkit-appearance:none;cursor:pointer;
  background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232F4A3D' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 1em center;background-size:16px 16px;
}
.form-row select:focus{outline:2px solid var(--gold);outline-offset:1px;}
.form-row.invalid select{border-color:#c0392b;}
/* Until a state is picked the value is "", and the placeholder option should
   look like the text fields' placeholders rather than like a real answer. */
.form-row select:invalid{color:rgba(47,74,61,.5);}
/* The list itself is drawn by the OS, so it does not inherit the page's
   colours - set them here or a dark-mode machine shows white-on-white. */
.form-row select option{color:var(--ink);background:#fff;}
.form-error{display:none;font-size:.78rem;color:#c0392b;}
.form-row.invalid .form-error{display:block;}
.form-success{
  display:flex;align-items:center;gap:.5em;margin:1rem 0 0;padding:.9em 1em;background:rgba(63,107,82,0.08);
  color:var(--green-deep);border-radius:10px;font-size:.9rem;font-weight:600;
}
.form-success svg{width:18px;height:18px;flex-shrink:0;}

/* footer */
.site-footer{background:var(--maroon);color:rgba(251,246,236,.75);padding:4rem 1.5rem 1.5rem;border-top:1px solid rgba(255,255,255,.1);}
.footer-inner{max-width:1060px;margin:0 auto;display:grid;grid-template-columns:1.4fr 1fr 1fr 1.25fr;gap:2.5rem;}
/* The registered-business block. `font-style:normal` because <address> is
   italic by default and this is an address, not an aside. */
.footer-address{
  font-style:normal;line-height:1.65;font-size:.88rem;
  color:rgba(251,246,236,.65);margin:0 0 1rem;
}
.footer-address strong{display:block;color:rgba(251,246,236,.85);font-weight:600;margin-bottom:.25em;}
/* The address is long enough to overflow a narrow column, and an email with
   no spaces in it cannot wrap on its own. */
.footer-mail{word-break:break-word;}
/* The footer sits on maroon, where the deep-green disc scores 1.24:1 and all
   but disappears. Use the light variant of the badge here instead. */
/* The footer serves the cream logo file; only the caption needs recolouring,
   since gold-deep is too dark to read on maroon. */
.site-footer .brand-sub{color:var(--gold);}
.site-footer .brand-logo{height:30px;}
.site-footer .brand-symbol{width:44px;height:44px;}
.footer-brand p{color:rgba(251,246,236,.65);font-size:.9rem;margin-top:1rem;max-width:320px;}
.footer-col h4{font-family:var(--font-body);font-size:.82rem;text-transform:uppercase;letter-spacing:.08em;color:var(--gold);margin-bottom:1rem;}
.footer-col a{display:flex;align-items:center;gap:.5em;text-decoration:none;color:rgba(251,246,236,.78);font-size:.92rem;margin-bottom:.7em;}
.footer-col a:hover{color:var(--cream);}
.footer-col a svg{width:15px;height:15px;}
/* The address is the map link. It keeps the address's own size and colour,
   and the pin sits at the first line rather than centred on all three. */
.footer-col .footer-map{align-items:flex-start;font-size:inherit;color:inherit;margin:0;}
.footer-col .footer-map svg{flex-shrink:0;margin-top:.3em;color:var(--gold);}
.footer-col .footer-map:hover{color:var(--cream);}
.footer-col .footer-map:hover span{text-decoration:underline;text-underline-offset:3px;}
.footer-bottom{max-width:1060px;margin:2.5rem auto 0;padding-top:1.5rem;border-top:1px solid rgba(255,255,255,.12);font-size:.82rem;color:rgba(251,246,236,.55);}

/* back to top */
/* ===== cart + checkout ===== */
.cart-btn{
  position:relative;background:none;border:1px solid var(--border);border-radius:12px;
  width:44px;height:44px;display:flex;align-items:center;justify-content:center;
  cursor:pointer;color:var(--ink);margin-left:.6rem;flex-shrink:0;transition:border-color .2s ease,color .2s ease;
}
.cart-btn:hover{border-color:var(--gold);color:var(--gold-deep);}
/* Same box as the cart button, but it is a link, so the underline has to go. */
.acct-btn{text-decoration:none;}
.acct-btn svg{width:20px;height:20px;}
.cart-btn svg{width:20px;height:20px;}
.cart-count{
  position:absolute;top:-7px;right:-7px;min-width:21px;height:21px;padding:0 5px;
  background:var(--gold);color:#fff;border-radius:999px;
  font-size:.72rem;font-weight:700;display:flex;align-items:center;justify-content:center;
  border:2px solid var(--cream);
}

.shop-actions{display:flex;gap:.5rem;margin-top:auto;padding-top:1rem;}
.shop-actions .btn-add{margin-top:0;flex:1;width:auto;}
.shop-actions .btn-buy{flex:1;}
.btn-buy{
  display:inline-flex;align-items:center;justify-content:center;gap:.4em;
  padding:.72em 1em;border-radius:999px;cursor:pointer;
  background:var(--gold);border:1.5px solid var(--gold);color:#fff;
  font-family:var(--font-body);font-weight:600;font-size:.92rem;
  transition:background .18s ease,border-color .18s ease,transform .18s ease;
}
.btn-buy:hover{background:var(--gold-deep);border-color:var(--gold-deep);transform:translateY(-1px);}
.btn-sm{padding:.55em 1.1em;font-size:.86rem;}
.btn-add{
  margin-top:1rem;width:100%;display:inline-flex;align-items:center;justify-content:center;gap:.45em;
  padding:.72em 1em;border-radius:999px;cursor:pointer;
  background:transparent;border:1.5px solid var(--gold);color:var(--gold-deep);
  font-family:var(--font-body);font-weight:600;font-size:.92rem;
  transition:background .18s ease,color .18s ease,transform .18s ease;
}
.btn-add svg{width:16px;height:16px;}
.btn-add:hover{background:var(--gold);color:#fff;transform:translateY(-1px);}
.btn-add.added{background:var(--green);border-color:var(--green);color:#fff;}

/* ===== out of stock =====
   Applied by script once /api/products answers, never in the built HTML: the
   page is static and the shelf is not, so the only honest source is the
   database at the moment someone looks. */
.shop-card.is-soldout{opacity:.75;}
/* The lift on hover reads as "you can click this". Nothing here is clickable. */
.shop-card.is-soldout:hover{transform:none;box-shadow:var(--shadow);}
.shop-card.is-soldout .shop-media img{filter:grayscale(1);}
/* "Most Loved" and "Out of stock" share the same corner, and a product can be
   both. The sold-out one wins, because it is the one that changes a decision. */
.shop-card.is-soldout .shop-badge{display:none;}
.soldout-badge{
  position:absolute;top:-11px;right:1.2rem;background:var(--ink);color:#fff;
  font-size:.72rem;font-weight:700;padding:.3em .8em;border-radius:999px;letter-spacing:.03em;
}
/* Disabled rather than hidden. A missing button looks like a broken card;
   a greyed one that says why does not. */
.shop-card.is-soldout .btn-add[disabled]{
  background:transparent;border-color:var(--border);color:var(--ink-soft);
  cursor:not-allowed;transform:none;
}
.shop-card.is-soldout .btn-add[disabled]:hover{
  background:transparent;color:var(--ink-soft);transform:none;
}

.scrim{position:fixed;top:0;right:0;bottom:0;left:0;background:rgba(26,34,28,.5);z-index:190;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);}

.cart{
  position:fixed;top:0;right:0;bottom:0;width:min(420px,92vw);z-index:200;
  background:var(--cream);border-left:1px solid var(--border);
  display:flex;flex-direction:column;
  transform:translateX(101%);transition:transform .3s cubic-bezier(.3,.8,.35,1);
  box-shadow:-14px 0 40px rgba(40,32,20,.18);visibility:hidden;
}
.cart.open{transform:translateX(0);visibility:visible;}
.cart-head{
  display:flex;align-items:center;justify-content:space-between;
  padding:1.15rem 1.25rem;border-bottom:1px solid var(--border);
}
.cart-head h3{margin:0;font-size:1.12rem;display:flex;align-items:center;gap:.5em;}
.cart-head h3 svg{width:19px;height:19px;color:var(--gold-deep);}
.icon-btn{
  background:none;border:none;cursor:pointer;color:var(--ink-soft);
  width:36px;height:36px;border-radius:9px;display:flex;align-items:center;justify-content:center;
}
.icon-btn:hover{background:rgba(43,38,32,.07);color:var(--ink);}
.icon-btn svg{width:19px;height:19px;}
.cart-body{flex:1;overflow-y:auto;padding:1rem 1.25rem;}
.cart-line{display:flex;gap:.85rem;padding:.9rem 0;border-bottom:1px solid var(--border);}
.cart-line:last-child{border-bottom:none;}
.cart-thumb{width:64px;height:52px;border-radius:10px;overflow:hidden;position:relative;flex-shrink:0;background:var(--cream-alt);}
.cart-thumb .cell{top:0;right:0;bottom:0;left:0;width:100%;height:100%;}
.cart-thumb.shop-media-icon{display:flex;align-items:center;justify-content:center;}
.cart-thumb.shop-media-icon svg{width:24px;height:24px;}
.cart-info{flex:1;min-width:0;}
.cart-name{font-weight:600;font-size:.93rem;display:block;margin-bottom:.15em;}
.cart-unit{font-size:.8rem;color:var(--ink-soft);}
.qty{display:inline-flex;align-items:center;gap:.1rem;margin-top:.5rem;border:1px solid var(--border);border-radius:999px;overflow:hidden;}
.qty button{
  background:none;border:none;cursor:pointer;width:28px;height:28px;
  display:flex;align-items:center;justify-content:center;color:var(--ink);
}
.qty button:hover{background:rgba(43,38,32,.07);}
.qty button svg{width:14px;height:14px;}
.qty span{min-width:24px;text-align:center;font-weight:600;font-size:.88rem;}
.cart-right{text-align:right;display:flex;flex-direction:column;justify-content:space-between;align-items:flex-end;}
.cart-lineprice{font-family:var(--font-display);font-size:1.02rem;color:var(--green);}
.cart-remove{background:none;border:none;cursor:pointer;color:var(--ink-soft);font-size:.76rem;text-decoration:underline;padding:0;}
.cart-remove:hover{color:#b3402f;}
.cart-empty{text-align:center;padding:3rem 1rem;color:var(--ink-soft);}
.cart-empty svg{width:42px;height:42px;color:var(--border);margin-bottom:.8rem;}
.cart-foot{padding:1.1rem 1.25rem 1.3rem;border-top:1px solid var(--border);background:var(--card-bg);}
.cart-row{display:flex;justify-content:space-between;align-items:center;padding:.3rem 0;font-size:.93rem;color:var(--ink-soft);}
.cart-row strong{color:var(--ink);font-weight:600;}
.cart-total{border-top:1px solid var(--border);margin-top:.5rem;padding-top:.7rem;font-size:1.02rem;}
.cart-total strong{font-family:var(--font-display);font-size:1.28rem;color:var(--green);}
.cart-note{font-size:.78rem;color:var(--gold-deep);margin:.5rem 0 .9rem;}

.co-page{
  position:fixed;top:0;right:0;bottom:0;left:0;z-index:300;background:var(--cream);
  overflow-y:auto;display:flex;flex-direction:column;
}
.co-topbar{
  position:sticky;top:0;z-index:2;
  display:flex;align-items:center;justify-content:space-between;gap:1rem;
  padding:.95rem 1.5rem;background:var(--card-bg);border-bottom:1px solid var(--border);
}
/* Same lockup as the header, in a button. Opacity rather than colour on
   hover, since the logo is an image and has no inheritable colour. */
.co-brand{
  display:inline-flex;align-items:center;gap:.5em;
  background:none;border:none;padding:0;cursor:pointer;
  transition:opacity .18s ease;
}
.co-brand:hover{opacity:.78;}
.co-brand .brand-logo{height:23px;}
.co-brand .brand-symbol{width:32px;height:32px;}
.co-shell{width:min(620px,100%);margin:0 auto;padding:2.2rem 1.5rem 3rem;flex:1;}
.co-shell > h3{font-size:1.65rem;margin:0 0 1.4rem;text-align:center;}
.steps{list-style:none;display:flex;gap:.4rem;margin:0;padding:0 0 1.5rem;}
.step{display:flex;align-items:center;gap:.4em;font-size:.8rem;color:var(--ink-soft);flex:1;font-weight:600;}
.step span{
  width:23px;height:23px;border-radius:50%;background:var(--border);color:var(--ink-soft);
  display:flex;align-items:center;justify-content:center;font-size:.74rem;flex-shrink:0;
}
.step.active{color:var(--ink);}
.step.active span{background:var(--gold);color:#fff;}
.step.done span{background:var(--green);color:#fff;}
.modal-body{padding:0;}
.form-grid{display:grid;grid-template-columns:1fr 1fr;gap:.9rem;}
.form-row textarea{
  padding:.8em 1em;border-radius:10px;border:1px solid var(--border);
  background:rgba(43,38,32,.03);color:var(--ink);font-size:.95rem;font-family:var(--font-body);resize:vertical;
}
.form-row textarea:focus{outline:2px solid var(--gold);outline-offset:1px;}
.form-row.invalid textarea{border-color:#c0392b;}

.demo-note{
  display:flex;gap:.6em;align-items:flex-start;
  background:rgba(191,143,58,.12);border:1px solid rgba(191,143,58,.3);
  border-radius:12px;padding:.8em 1em;font-size:.84rem;color:var(--ink);margin:0 0 1.1rem;
}
.demo-note svg{width:17px;height:17px;color:var(--gold-deep);flex-shrink:0;margin-top:.1em;}

.pay-list{display:flex;flex-direction:column;gap:.6rem;}
.pay{
  display:flex;align-items:center;gap:.8rem;cursor:pointer;
  border:1.5px solid var(--border);border-radius:14px;padding:.85rem 1rem;
  background:var(--card-bg);transition:border-color .18s ease,background .18s ease;
}
.pay:hover{border-color:rgba(191,143,58,.6);border-color:color-mix(in srgb,var(--gold) 55%,var(--border));}
.pay input{accent-color:var(--gold);width:17px;height:17px;flex-shrink:0;}
/* Two selectors for one state. :has() is recent - Firefox only got it in 121,
   Samsung Internet in 20 - and this is the ONLY thing marking which payment
   method is chosen, so without it a customer cannot tell what they picked.
   The .selected class is set by a change handler in the script below and
   works everywhere; :has() stays so it is still correct with JS disabled. */
.pay:has(input:checked),
.pay.selected{border-color:var(--gold);background:rgba(191,143,58,.08);}
.pay-ic{width:38px;height:38px;border-radius:10px;background:var(--cream-alt);display:flex;align-items:center;justify-content:center;flex-shrink:0;}
.pay-ic svg{width:19px;height:19px;color:var(--gold-deep);}
.pay-txt{display:flex;flex-direction:column;gap:.1em;}
.pay-txt strong{font-size:.94rem;}
.pay-txt em{font-style:normal;font-size:.78rem;color:var(--ink-soft);}

.co-summary{margin-top:1.2rem;border-top:1px solid var(--border);padding-top:.9rem;}
.co-summary .cart-row{font-size:.88rem;}
.co-done{text-align:center;padding:1rem 0;}
.co-done h4{font-size:1.3rem;margin:0 0 .35em;}

/* ===== the printed receipt =====

   The paper unrolls downward out of the top of its container, which is why
   .receipt clips and .receipt-paper is what moves. clip-path does the reveal
   rather than height, so nothing below it reflows a frame at a time while the
   animation runs. */
.receipt{
  position:relative;
  overflow:hidden;
  max-width:420px;margin:0 auto;
  padding-top:.7rem;
}
/* The slot the paper feeds out of - a thin shadow across the top that the
   receipt appears from underneath. */
.receipt::before{
  content:"";position:absolute;left:8%;right:8%;top:0;height:3px;border-radius:3px;
  background:linear-gradient(90deg, transparent, rgba(59,45,30,.18) 18%, rgba(59,45,30,.18) 82%, transparent);
}
.receipt-paper{
  position:relative;
  background:#FFFDF8;
  border:1px solid var(--border);
  border-bottom:none;
  border-radius:10px 10px 0 0;
  padding:1.6rem 1.4rem 1.8rem;
  text-align:center;
  box-shadow:0 14px 30px rgba(59,45,30,.10);
}
/* The torn-off bottom edge. Two gradients meeting at a point, tiled - the
   paper's own colour above the tear, nothing below it. */
.receipt-paper::after{
  content:"";position:absolute;left:-1px;right:-1px;bottom:-11px;height:12px;
  background:
    linear-gradient(-45deg, transparent 0 8px, #FFFDF8 8px 100%) 0 0/16px 12px repeat-x,
    linear-gradient( 45deg, transparent 0 8px, #FFFDF8 8px 100%) 0 0/16px 12px repeat-x;
  filter:drop-shadow(0 3px 2px rgba(59,45,30,.07));
}
@keyframes receiptRoll{
  0%   { clip-path:inset(0 0 100% 0); transform:translateY(-18px) scaleY(.985); }
  70%  { clip-path:inset(0 0 4% 0);   transform:translateY(2px)   scaleY(1.004); }
  100% { clip-path:inset(0 0 0 0);    transform:translateY(0)     scaleY(1); }
}
/* Each line appears as the paper reaches it, like text being printed onto it
   rather than the whole receipt arriving pre-written. */
@keyframes receiptLine{
  from{ opacity:0; transform:translateY(6px); }
  to  { opacity:1; transform:translateY(0); }
}
/* A small settle once the check lands, so the tick has a beat of its own. */
@keyframes rtPop{
  0%  { transform:scale(1); }
  45% { transform:scale(1.13); }
  100%{ transform:scale(1); }
}
/* And one soft ring pushing outward from it, then gone. */
@keyframes rtHalo{
  from{ opacity:.5; transform:scale(.55); }
  to  { opacity:0;  transform:scale(1.5); }
}

/* The tick draws itself: ring first, then the check on top of it. */
.receipt-tick{position:relative;width:64px;height:64px;margin:0 auto .95rem;}
.receipt-tick::after{
  content:"";position:absolute;inset:0;border-radius:50%;
  border:2px solid var(--green);opacity:0;pointer-events:none;
}
.receipt-tick svg{width:100%;height:100%;display:block;}
.rt-ring{fill:none;stroke:var(--green);stroke-width:3;stroke-dasharray:145;}
.rt-check{
  fill:none;stroke:var(--green);stroke-width:4;
  stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:42;
}
@keyframes rtRing{ from{ stroke-dashoffset:145; } to{ stroke-dashoffset:0; } }
@keyframes rtCheck{ from{ stroke-dashoffset:42; } to{ stroke-dashoffset:0; } }

/* The animations are added here rather than being the default, and none of
   them uses a fill mode. That means the finished receipt - paper unrolled,
   tick drawn - is what the element looks like with no animation running at
   all. It matters because the alternative is what this first did: hide the
   paper with clip-path and hide the tick with a dash offset, then rely on the
   animation to reveal them. Anything that stops those animations - a reduced
   motion setting, a browser that does not know clip-path animation, a frozen
   background tab - would leave a customer looking at a blank confirmation for
   an order that really was placed. Motion is the decoration; it can fail. */
@media (prefers-reduced-motion: no-preference){
  /* Slower than it wants to be. The whole thing runs about 2.4s, which is
     long for an animation and right for this one - it is the only moment in
     the flow worth pausing on, and a receipt that snaps into place does not
     feel like anything was printed. */
  .receipt.is-printing .receipt-paper{ animation:receiptRoll 1.5s cubic-bezier(.18,.72,.24,1); }

  /* The tick: ring draws, check draws inside it, then both settle together
     with one ring pushing outward. */
  .receipt.is-printing .rt-ring { animation:rtRing  .85s ease-out .55s backwards; }
  .receipt.is-printing .rt-check{ animation:rtCheck .55s ease-out 1.25s backwards; }
  .receipt.is-printing .receipt-tick      { animation:rtPop  .5s ease-out 1.7s backwards; }
  .receipt.is-printing .receipt-tick::after{ animation:rtHalo .7s ease-out 1.75s backwards; }

  /* The lines print in order, chasing the paper down the page. Listed rather
     than looped because the item count varies with the order; ten covers the
     heading, the four meta rows and a basket bigger than anyone has sent. */
  .receipt.is-printing .receipt-paper h4,
  .receipt.is-printing .receipt-lead,
  .receipt.is-printing .receipt-meta div,
  .receipt.is-printing .receipt-items .cart-row,
  .receipt.is-printing .receipt-foot,
  .receipt.is-printing .demo-note{
    animation:receiptLine .55s ease-out backwards;
  }
  .receipt.is-printing .receipt-paper h4          { animation-delay:.30s; }
  .receipt.is-printing .receipt-lead              { animation-delay:.42s; }
  .receipt.is-printing .receipt-meta div:nth-child(1){ animation-delay:.62s; }
  .receipt.is-printing .receipt-meta div:nth-child(2){ animation-delay:.71s; }
  .receipt.is-printing .receipt-meta div:nth-child(3){ animation-delay:.80s; }
  .receipt.is-printing .receipt-meta div:nth-child(4){ animation-delay:.89s; }
  .receipt.is-printing .receipt-items .cart-row:nth-child(1){ animation-delay:1.02s; }
  .receipt.is-printing .receipt-items .cart-row:nth-child(2){ animation-delay:1.10s; }
  .receipt.is-printing .receipt-items .cart-row:nth-child(3){ animation-delay:1.18s; }
  .receipt.is-printing .receipt-items .cart-row:nth-child(4){ animation-delay:1.26s; }
  .receipt.is-printing .receipt-items .cart-row:nth-child(5){ animation-delay:1.34s; }
  .receipt.is-printing .receipt-items .cart-row:nth-child(6){ animation-delay:1.42s; }
  .receipt.is-printing .receipt-items .cart-row:nth-child(7){ animation-delay:1.50s; }
  .receipt.is-printing .receipt-items .cart-row:nth-child(8){ animation-delay:1.58s; }
  .receipt.is-printing .receipt-items .cart-row:nth-child(9){ animation-delay:1.66s; }
  .receipt.is-printing .receipt-items .cart-row:nth-child(n+10){ animation-delay:1.74s; }
  .receipt.is-printing .receipt-foot              { animation-delay:1.95s; }
  .receipt.is-printing .demo-note        { animation-delay:2.08s; }
}

.receipt-lead{font-size:.9rem;color:var(--ink-soft);margin:0 0 1.1rem;}

/* Order number, date, method: label left, value right, dot leaders between,
   the way a till receipt sets them. */
.receipt-meta{
  margin:0 0 1rem;padding:.8rem 0;text-align:left;
  border-top:1px dashed var(--border);border-bottom:1px dashed var(--border);
  font-size:.82rem;
}
.receipt-meta div{display:flex;justify-content:space-between;gap:1em;padding:.16rem 0;}
.receipt-meta dt{color:var(--ink-soft);margin:0;}
.receipt-meta dd{margin:0;font-weight:600;font-variant-numeric:tabular-nums;text-align:right;}

.receipt-items{text-align:left;}
.receipt-items .cart-row{font-size:.88rem;}
.receipt-items .cart-total{
  border-top:1px dashed var(--border);margin-top:.5rem;padding-top:.5rem;
}
.receipt-foot{
  margin:1.1rem 0 0;font-family:var(--font-display);font-size:.9rem;color:var(--green-deep);
}
.co-done .demo-note{margin:1rem 0 0;text-align:left;}


.modal-foot{
  display:flex;gap:.7rem;justify-content:flex-end;
  padding:1.4rem 0 0;margin-top:1.6rem;border-top:1px solid var(--border);
}

@media (max-width:560px){
  .form-grid{grid-template-columns:1fr;}
  .co-shell{padding:1.6rem 1.15rem 2.4rem;}
  .co-shell > h3{font-size:1.4rem;}
  .modal-foot .btn{flex:1;justify-content:center;}
  /* .72rem was 11.5px - under the 12px floor where small text starts costing
     readability on a phone, and these three words are the only thing telling
     someone how far through checkout they are. */
  .step{font-size:.78rem;}
  /* 2rem of padding each side is a lot of a 320px screen to spend on nothing. */
  .join-form{padding:1.3rem;}
  .shop-actions{flex-direction:column;}
}

/* ===== even numerals =====
   Georgia ships old-style figures (3,5,7,9 drop below the baseline; 6,8 rise),
   so numbers looked misaligned. Use lining + tabular figures for all numeric text. */
.price,.stat-value,.pricing-row strong,.cart-lineprice,.cart-total strong,.benefit-num,.savings-highlight{
  font-family:var(--font-body);
  font-variant-numeric:lining-nums tabular-nums;
  font-feature-settings:"lnum" 1,"tnum" 1;
  font-weight:600;
  letter-spacing:-.012em;
}
.stat-value{font-weight:700;letter-spacing:-.02em;}
.cart-total strong,.pricing-row strong{font-weight:700;}
.cart-row,.pricing-row,.co-summary,.qty span,.ritual-tag,.cart-unit{
  font-variant-numeric:tabular-nums;
  font-feature-settings:"tnum" 1;
}

.back-to-top{
  position:fixed;right:1.4rem;bottom:1.4rem;width:46px;height:46px;border-radius:50%;
  background:var(--gold);color:#fff;border:none;display:flex;align-items:center;justify-content:center;
  cursor:pointer;box-shadow:0 10px 24px rgba(191,143,58,.3);opacity:0;pointer-events:none;
  transform:translateY(10px);transition:opacity .25s ease, transform .25s ease;z-index:90;
}
.back-to-top.visible{opacity:1;pointer-events:auto;transform:translateY(0);}
.back-to-top svg{width:20px;height:20px;}

/* ===== aspect-ratio fallback (Chrome < 88) =====

   Without aspect-ratio these boxes have no height at all - they are empty
   elements whose only content is absolutely positioned - so the cow photos,
   the product images and the Instagram grid all collapse to nothing and the
   sections look broken rather than merely plain.

   .shop-media holds its child in position:absolute, so a pseudo-element with
   percentage padding reserves the height without disturbing it - percentage
   padding resolves against WIDTH, which is what makes the ratio work. The two
   herd boxes have a fixed 94px width, so they can just be told their height.
   width, so they can just be told their height. */
@supports not (aspect-ratio: 1 / 1){
  .shop-media::before{content:"";display:block;padding-bottom:66.667%;}
  .herd-avatar{height:94px;}
  .herd-avatar .cell{height:125px;}
}

/* ===== touch targets =====

   Keyed on (pointer:coarse) rather than a width, because what matters is
   whether the thing doing the tapping is a fingertip - a touch laptop at
   1440px has the same problem a phone does, and a narrow window on a desktop
   does not. Mouse users see none of this.

   Measured before writing it: Add to Cart and Buy Now were 33px tall, the
   Member/Regular toggle 26px, the carousel dots 8x8. The usual floor is 44px
   (Apple) / 48dp (Material); everything below is a button people miss.

   Nothing here changes how anything looks on a mouse, and on touch only the
   hit area grows - the dots keep their exact size and shape. */
@media (pointer:coarse){
  .btn-add,.btn-buy{min-height:44px;}
  .rate-btn{min-height:44px;padding-left:1em;padding-right:1em;}
  .carousel-btn{width:44px;height:44px;}
  .nav-toggle{width:44px;height:44px;}
  .co-brand,.co-topbar .btn{min-height:44px;}
  /* The "Sign in" offered beside the pre-registration and checkout forms. */
  .signin-strip a{display:inline-flex;align-items:center;min-height:44px;}

  /* These are already flex rows, so min-height centres the label without
     moving it. margin-bottom goes, because the added height now supplies the
     spacing the list used to get from the margin. */
  .footer-col a{min-height:44px;margin-bottom:0;}
  .footer-col .footer-map{min-height:0;}
  .text-link{min-height:44px;}

  /* The dot moves into a pseudo-element so the button itself can be a 44px
     target while the visible dot stays 8px. The active pill (22px wide) moves
     with it, so the animation is unchanged. */
  .carousel-dots{gap:0;}
  .carousel-dots button{
    width:44px;height:44px;padding:0;border:none;background:none;border-radius:0;
    display:flex;align-items:center;justify-content:center;
  }
  .carousel-dots button::before{
    content:"";display:block;width:8px;height:8px;border-radius:50%;
    background:var(--border);transition:width .2s ease;
  }
  .carousel-dots button.active{width:44px;background:none;}
  .carousel-dots button.active::before{width:22px;border-radius:4px;background:var(--gold);}

  /* ----- the cart drawer, which the first pass over this missed -----

     Measured on a 375px phone: the quantity − and + were 28x28, Remove was
     45x14 and Close cart 36x36. Remove sits directly beside the minus, so
     someone lowering a quantity by one taps a 14px-tall target next to a
     28px one and deletes the line instead. This is the most expensive miss
     on the site - it happens with a full cart, one tap from paying.

     The buttons grow to 44px. The pill they sit in is inline-flex, so the
     row grows with them and nothing needs repositioning. */
  .qty button{min-width:44px;min-height:44px;}
  .qty span{min-width:32px;}
  .icon-btn{min-width:44px;min-height:44px;}

  /* Remove is a text link, and making the text 44px tall would push it away
     from the line it belongs to. Instead the visible underlined word stays
     exactly as it is and an invisible ::before stretches the tap area around
     it - the same trick the carousel dots above use. */
  .cart-remove{position:relative;}
  .cart-remove::before{
    content:"";position:absolute;left:50%;top:50%;
    width:max(100%,44px);height:44px;transform:translate(-50%,-50%);
  }

  /* ----- iOS zooms into any field smaller than 16px -----

     Safari on iPhone zooms the whole page in when a text field with a
     computed font-size under 16px receives focus, and because the viewport
     meta sets no maximum-scale it does NOT zoom back out afterwards. The
     visitor is left on a magnified page that now scrolls sideways, which
     reads as the site being broken rather than as a zoom.

     Measured at 390x844: every checkout and pre-registration field was
     15.2px and the assistant's box 14.08px, so every form on the site did
     this - on the two screens where it costs the most, checkout and the
     membership form.

     16px exactly, and only on touch, so nothing about the desktop layout
     moves. select is included: iOS zooms for those too. */
  input[type="text"],input[type="tel"],input[type="email"],input[type="number"],
  input[type="search"],input[type="password"],textarea,select{
    font-size:16px;
  }

  /* ----- the mobile menu -----

     The links were 66x33. Their gold underline is an ::after pinned to the
     bottom of the link box, so adding height or padding would drag the
     underline away from the word it marks. Same solution: the link is left
     alone and ::before does the reaching.

     left/right 0 keeps the area inside the link's own width, so in the
     horizontal desktop nav neighbouring links cannot overlap either. */
  .nav-link::before{
    content:"";position:absolute;left:0;right:0;top:50%;
    height:44px;transform:translateY(-50%);
  }
}

/* responsive */
@media (max-width:900px){
  .story-inner,.pricing-inner,.join-inner{grid-template-columns:1fr;}
  .benefit-grid{grid-template-columns:repeat(2,1fr);}
  .herd-grid{grid-template-columns:repeat(2,1fr);}
  .shop-grid{grid-template-columns:repeat(2,1fr);}
  .stats-grid{grid-template-columns:repeat(2,1fr);}
  /* Four footer columns get too narrow here - the address starts breaking
     mid-word. Two by two until the 720px rule stacks them entirely. */
  .footer-inner{grid-template-columns:1fr 1fr;gap:2rem 2.5rem;}
}
/* The header runs out of room well before the phone breakpoint.

   Measured at 768px (iPad portrait): brand 119px + nav 552px + the account
   and cart buttons 88px + gaps came to 803px against a 768px viewport, so the
   cart button - the one that matters most - sat 35px off the right edge with
   no way to scroll to it, because the hamburger did not appear until 720px.

   So the drawer rules live here at 860px, separate from the 720px block,
   which is about grids and the hero and is right where it is. 860 rather than
   820 leaves room for the nav to reflow a little wider on other platforms. */
@media (max-width:860px){
  .main-nav{
    position:fixed;top:0;right:0;bottom:0;left:auto;top:64px;width:min(320px,85vw);
    /* 100vh is the viewport with the address bar HIDDEN. On Android Chrome
       the bar is usually showing, so a 100vh drawer runs off the bottom of
       the screen and the last item - Reserve a Seat - cannot be reached.
       iOS behaves differently, which is why this only shows up on Android.

       dvh is the height actually visible right now. The vh line above stays
       as the fallback for browsers that do not know dvh, and overflow-y
       guarantees the bottom is reachable either way. */
    height:calc(100vh - 64px);
    height:calc(100dvh - 64px);
    overflow-y:auto;overscroll-behavior:contain;
    background:var(--cream);border-left:1px solid var(--border);flex-direction:column;align-items:flex-start;
    padding:2rem 1.6rem;gap:1.4rem;transform:translateX(100%);
    transition:transform .25s ease, visibility .25s ease;
    visibility:hidden;
    box-shadow:-10px 0 30px rgba(0,0,0,.12);
  }
  .main-nav.open{transform:translateX(0);visibility:visible;}
  .nav-cta{width:100%;justify-content:center;}
  .nav-toggle{display:flex;}
}

@media (max-width:720px){
  .benefit-grid{grid-template-columns:repeat(2,1fr);gap:.6rem;}
  .benefit-card{padding:.85rem;}
  .benefit-title{font-size:.9rem;}
  .herd-grid{grid-template-columns:repeat(2,1fr);}
  .shop-grid{grid-template-columns:repeat(2,1fr);gap:.7rem;}
  .shop-card{padding:.8rem;}
  .shop-card h3{font-size:.94rem;}
  .shop-card p{font-size:.78rem;margin-bottom:.6rem;}
  .price{font-size:1.05rem;}
  .btn-add,.btn-buy{font-size:.78rem;padding:.6em .5em;}
  /* Phones: one large photo at a time in a row you swipe, snapping to each,
     rather than four thumbnails. The row runs edge to edge, so the next
     photo peeking in shows there is more. */
  .gallery-grid{
    display:flex;gap:.8rem;overflow-x:auto;scroll-snap-type:x mandatory;
    margin:0 -1.5rem;padding:0 1.5rem .4rem;scrollbar-width:none;
    -webkit-overflow-scrolling:touch;
  }
  .gallery-grid::-webkit-scrollbar{display:none;}
  .gallery-item{flex:0 0 80vw;scroll-snap-align:center;}
  .gallery-item img{height:min(62vh,380px);}
  .gallery-item figcaption{font-size:.82rem;padding:1.4rem .9rem .75rem;}
  .footer-inner{grid-template-columns:1fr;}

  .hero{min-height:auto;padding:2.25rem 1.25rem clamp(210px,55vw,300px);}
  /* On phones keep the scene as a bottom band: filling a tall narrow screen
     would crop most of the width and cut the figures out of frame. */
  .hero-scene{top:auto;height:clamp(175px,46vw,265px);}
  .hero-logo{margin-bottom:1.4rem;}
}

@media (prefers-reduced-motion: reduce){
  .hero::before,.hero::after{animation:none;}
  .hero-scene *{animation:none !important;}
  .hero-inner > *,.hero-logo,.hero-logo-tag,.hero-scene{animation:none !important;}
  .hero-actions .btn-primary svg,.hero-actions .btn-primary i{animation:none !important;}
  .process-bg{display:none;}
  .membership-banner img{transition:none;}
  .gallery-item img{transition:none;}
  .trust-track{animation:none;}
  .reveal{animation:none !important;opacity:1;transform:none;}
  .gallery-item.reveal{clip-path:none;}
  img[data-blur]{filter:none;transform:none;transition:none;}
  html{scroll-behavior:auto;}
}

/* ---------------- chat widget ---------------- */

.zv-chat{position:fixed;right:1.4rem;bottom:5.6rem;z-index:400;font-family:var(--font-body);display:flex;align-items:center;gap:.55rem;transition:opacity .18s ease,visibility .18s ease;}

/*
  Out of the way while the cart drawer or checkout is open.

  The assistant is pinned bottom-right at z-index 400, above both, so it
  floats over the cart total and the checkout buttons - exactly where someone
  is trying to tap. The class is set by syncChatVisibility() in the cart
  script, off state the cart already tracks.

  This began as `body:has(.cart.open) .zv-chat`. The selector matched - both
  :has() support and the rule matching the element were confirmed in the
  browser - and the element still computed to visible, so it is driven from
  JS instead rather than left half-working.

  visibility rather than display:none so it fades instead of vanishing, and
  pointer-events so it cannot be tapped during the fade.
*/
body.zv-hide-chat .zv-chat{
  opacity:0;visibility:hidden;pointer-events:none;
}

.zv-chat-tag{
  display:inline-flex;align-items:center;gap:.45rem;
  padding:.36rem .7rem;border-radius:999px;
  background:var(--card-bg);border:1px solid var(--border);
  box-shadow:0 6px 16px rgba(36,56,45,.16);
  font-size:.74rem;font-weight:600;letter-spacing:.015em;
  color:var(--ink);white-space:nowrap;cursor:pointer;user-select:none;
  transition:transform .2s ease,box-shadow .2s ease;
  animation:zvTagIn .5s ease both .8s;
}
.zv-chat-tag:hover{transform:translateY(-2px);box-shadow:0 9px 20px rgba(36,56,45,.22);}
.zv-chat-tag-dot{width:7px;height:7px;border-radius:50%;background:var(--green);position:relative;flex:none;}
.zv-chat-tag-dot::after{content:"";position:absolute;top:0;right:0;bottom:0;left:0;border-radius:50%;background:var(--green);animation:zvTagPulse 2.2s ease-out infinite;}
.zv-chat.open .zv-chat-tag{display:none;}
@keyframes zvTagIn{from{opacity:0;transform:translateX(10px);}to{opacity:1;transform:none;}}
@keyframes zvTagPulse{0%{transform:scale(1);opacity:.5;}70%{transform:scale(2.4);opacity:0;}100%{transform:scale(2.4);opacity:0;}}
.zv-chat-toggle{
  width:58px;height:58px;border-radius:50%;border:none;cursor:pointer;
  background:var(--green);color:var(--cream);
  display:flex;align-items:center;justify-content:center;position:relative;
  box-shadow:0 10px 24px rgba(36,56,45,.35);
  transition:transform .2s ease,background .2s ease;
}
.zv-chat-toggle:hover{transform:translateY(-2px);background:var(--green-deep);}
.zv-chat-toggle svg{width:24px;height:24px;}
.zv-chat-toggle .zv-ic-close{position:absolute;}
.zv-chat.open .zv-ic-open{display:none;}
.zv-chat:not(.open) .zv-ic-close{display:none;}
.zv-chat-ping{
  position:absolute;top:-2px;right:-2px;width:14px;height:14px;border-radius:50%;
  background:var(--gold);border:2px solid var(--cream);
}
.zv-chat.opened .zv-chat-ping{display:none;}

.zv-chat-panel{
  position:absolute;right:0;bottom:calc(100% + .85rem);width:368px;max-width:88vw;
  height:min(520px,72vh);height:min(520px,72dvh);background:var(--card-bg);border:1px solid var(--border);
  border-radius:var(--radius);box-shadow:var(--shadow);display:flex;flex-direction:column;
  overflow:hidden;transform-origin:bottom right;
  animation:zvPanelIn .22s ease both;
}
@keyframes zvPanelIn{from{opacity:0;transform:translateY(12px) scale(.98);}to{opacity:1;transform:none;}}

.zv-chat-head{display:flex;align-items:center;gap:.7rem;padding:.9rem 1rem;background:var(--green-deep);color:var(--cream);}
.zv-chat-avatar{width:34px;height:34px;border-radius:50%;background:rgba(251,246,236,.14);display:flex;align-items:center;justify-content:center;flex:none;}
.zv-chat-avatar svg{width:18px;height:18px;}
.zv-chat-head-text{display:flex;flex-direction:column;line-height:1.25;flex:1;min-width:0;}
.zv-chat-head-text strong{font-family:var(--font-display);font-size:1rem;}
.zv-chat-head-text span{font-size:.76rem;opacity:.8;}
.zv-chat-close{background:none;border:none;color:var(--cream);opacity:.85;cursor:pointer;padding:.3rem;line-height:0;flex:none;}
.zv-chat-close:hover{opacity:1;}
.zv-chat-close svg{width:18px;height:18px;}

.zv-chat-body{flex:1;overflow-y:auto;padding:1rem;display:flex;flex-direction:column;gap:.6rem;background:var(--cream-alt);}
.zv-msg{max-width:86%;padding:.62rem .85rem;border-radius:14px;font-size:.9rem;line-height:1.45;}
.zv-msg p{margin:0 0 .5em;}
.zv-msg p:last-child{margin-bottom:0;}
.zv-msg ul{margin:.3em 0 .2em;padding-left:1.1em;}
.zv-msg li{margin-bottom:.2em;}
.zv-msg-bot{align-self:flex-start;background:var(--card-bg);border:1px solid var(--border);color:var(--ink);border-bottom-left-radius:4px;}
.zv-msg-user{align-self:flex-end;background:var(--green);color:var(--cream);border-bottom-right-radius:4px;}
.zv-msg a{color:inherit;font-weight:600;text-decoration:underline;text-underline-offset:2px;}
.zv-msg-bot a{color:var(--green-deep);}
.zv-cta{display:inline-flex;align-items:center;gap:.3em;margin-top:.4em;font-size:.83rem;font-weight:600;color:var(--gold-deep);text-decoration:none;}
.zv-cta svg{width:14px;height:14px;}
.zv-typing{align-self:flex-start;display:flex;gap:4px;padding:.7rem .9rem;background:var(--card-bg);border:1px solid var(--border);border-radius:14px;border-bottom-left-radius:4px;}
.zv-typing span{width:6px;height:6px;border-radius:50%;background:var(--ink-soft);opacity:.5;animation:zvBlink 1s infinite ease-in-out;}
.zv-typing span:nth-child(2){animation-delay:.15s;}
.zv-typing span:nth-child(3){animation-delay:.3s;}
@keyframes zvBlink{0%,80%,100%{opacity:.3;transform:scale(.85);}40%{opacity:1;transform:scale(1);}}

.zv-chat-suggest{display:flex;flex-wrap:wrap;gap:.4rem;padding:.6rem 1rem;border-top:1px solid var(--border);background:var(--card-bg);}
.zv-chip{
  border:1px solid var(--border);background:var(--cream-alt);color:var(--ink);
  font-family:var(--font-body);font-size:.78rem;padding:.4rem .7rem;border-radius:999px;
  cursor:pointer;transition:background .15s ease,border-color .15s ease;
}
.zv-chip:hover{background:var(--cream);border-color:var(--gold);}

.zv-chat-form{display:flex;gap:.5rem;padding:.75rem;border-top:1px solid var(--border);background:var(--card-bg);}
.zv-chat-form input{
  flex:1;border:1px solid var(--border);border-radius:12px;padding:.6rem .8rem;
  font-family:var(--font-body);font-size:.88rem;color:var(--ink);background:var(--cream-alt);
}
.zv-chat-form input:focus{outline:2px solid var(--gold);outline-offset:1px;}
.zv-chat-form button{
  width:40px;height:40px;border-radius:10px;border:none;background:var(--gold);color:#fff;
  display:flex;align-items:center;justify-content:center;cursor:pointer;flex:none;
}
.zv-chat-form button:hover{background:var(--gold-deep);}
.zv-chat-form button svg{width:17px;height:17px;}

.zv-chat-foot{margin:0;padding:.5rem 1rem .7rem;font-size:.68rem;color:var(--ink-soft);text-align:center;background:var(--card-bg);}
.zv-chat-foot a{color:var(--ink-soft);}

@media (max-width:640px){
  .zv-chat{right:1rem;bottom:4.9rem;gap:.45rem;}

  /* The "AI Assistant" pill sits to the left of the round button, and on a
     375px screen it reached 82px across the hero's "See How It's Made"
     button - so a tap meant for that button opened the chat instead.

     Hidden rather than moved, because there is nowhere on a phone it can sit
     without covering something, and it explains a button whose own
     aria-label already says the same thing. The pill is aria-hidden, so
     nothing is lost to a screen reader either. */
  .zv-chat-tag{display:none;}
  .zv-chat-panel{
    position:fixed;right:.6rem;left:.6rem;bottom:4.9rem;width:auto;max-width:none;
    height:min(70vh,540px);height:min(70dvh,540px);
  }
}
@media (prefers-reduced-motion:reduce){
  .zv-chat-tag{animation:none;}
  .zv-chat-tag-dot::after{animation:none;opacity:0;}
}

/* ---- the veil shown while leaving for another page ----

   The account and sign-in pages are rendered on the server, and a link to one
   of them gives no sign of having been followed until that answer arrives - the
   page just sits there, then goes blank. This covers the wait with the grazing
   cow from the hero, so a tap visibly did something.

   Kept in the document and faded in, rather than built on the click: the
   browser stops running scripts and loading images the moment it starts to
   navigate, so anything not already here might never be painted. */
.page-leave{
  position:fixed;top:0;right:0;bottom:0;left:0;z-index:500;
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:1.2rem;
  background:var(--cream);
  opacity:0;visibility:hidden;transition:opacity .3s ease,visibility 0s linear .3s;
}
.page-leave.on{opacity:1;visibility:visible;transition:opacity .3s ease;}
.page-leave svg{width:min(340px,78vw);height:auto;display:block;overflow:visible;}
/* Nothing here should cost anything while the veil is out of sight. */
.page-leave:not(.on) *{animation-play-state:paused !important;}
.pl-sun{fill:var(--green);opacity:.16;}
.pl-ground{fill:none;stroke:var(--ink);stroke-width:1.6;stroke-linecap:round;opacity:.2;}
.page-leave .zc-shadow{fill:#3E4A2E;opacity:.18;}
/* The head and neck piece of the cow picture turns at the top of the
   shoulders - 54% across and 20% down the (mirrored) picture - where the cut
   between the two pieces meets the back, so the back line never steps. A
   smaller nod than the drawn cow's neck made, for the same reason: one
   picture bends less gracefully than a drawn neck. Same rhythm. */
.pl-head{transform-box:fill-box;transform-origin:54% 20%;animation:plGraze 5s ease-in-out infinite;}
/* Down to the grass, a few tugs at it, then up to chew. */
@keyframes plGraze{
  0%,100%{transform:rotate(1deg);}
  16%{transform:rotate(14deg);}
  24%{transform:rotate(11.5deg);}
  32%{transform:rotate(14deg);}
  40%{transform:rotate(11.5deg);}
  48%{transform:rotate(14deg);}
  56%{transform:rotate(11.5deg);}
  64%{transform:rotate(14deg);}
  82%{transform:rotate(1deg);}
}
.page-leave-text{
  margin:0;font-family:var(--font-display);font-size:1.15rem;color:var(--ink);
  display:flex;align-items:baseline;
}
.page-leave-dots i{
  display:inline-block;width:5px;height:5px;margin-left:5px;border-radius:50%;background:var(--gold);
  animation:zvBlink 1.2s infinite both;
}
.page-leave-dots i:nth-child(2){animation-delay:.15s;}
.page-leave-dots i:nth-child(3){animation-delay:.3s;}
@media (prefers-reduced-motion:reduce){
  .page-leave,.page-leave.on{transition:none;}
  .page-leave *{animation:none !important;}
}
