/* ============================================================
   hai Farmer — storefront
   Visual language follows the Hatbazar reference: white page,
   flat pastel promo panels, bordered product cards, red prices,
   green actions, small radii, minimal shadow.
   ============================================================ */

/* ---------- 1. TOKENS ---------- */
:root{
  --green:#269C53;
  --green-dark:#1E7E42;
  --green-soft:#EAF6EF;
  --lime:#A8D84A;

  --orange:#FFA800;
  --orange-dark:#F08800;
  --red:#EE3A23;
  --red-dark:#D32B16;
  --star:#FFB800;

  --ink:#1B1B1B;
  --ink-70:#4A4A4A;
  --ink-50:#808080;
  --ink-30:#A9A9A9;
  --line:#EAEAEA;
  --line-2:#DDDDDD;

  --bg:#FFFFFF;
  --bg-2:#F7F8F7;
  --tint:#F6F7F5;

  --r-xs:6px; --r-sm:8px; --r-md:12px; --r-lg:16px; --r-pill:999px;
  --shadow-sm:0 1px 4px rgba(0,0,0,.04);
  --shadow-md:0 8px 24px -10px rgba(0,0,0,.16);

  --ff-display:'Quicksand',system-ui,sans-serif;
  --ff-body:'Lato',system-ui,sans-serif;

  --container:1320px;
  --pad:clamp(14px,3vw,30px);
  --sec:clamp(38px,4.6vw,62px);

  /* Inner-banner scrim, as raw channels so pages.css can mix its own
     alphas. theme-lux.css §1 restates this line in the theme's own ink. */
  --scrim-rgb:22,22,22;
}

/* ---------- 2. BASE ---------- */
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
html{-webkit-text-size-adjust:100%;overflow-x:clip}
body{
  font-family:var(--ff-body);background:var(--bg);color:var(--ink);
  font-size:15px;line-height:1.6;-webkit-font-smoothing:antialiased;
  /* `clip`, not `hidden`, on both elements.
     overflow-x:hidden on body alone propagates to the viewport, which leaves
     nothing stopping a touchpad or iOS rubber-band pan sideways — that pan is
     what showed page background beside the content. Setting it on html too
     stops the propagation and kills the pan.
     It has to be `clip` because `hidden` would make body a scroll container
     and break the sticky header (§4); `clip` never scrolls, so the header
     keeps sticking to the viewport. `clip` also pairs legally with a visible
     overflow-y, where `hidden` would silently force it to `auto`. */
  overflow-x:clip;width:100%;
}
body.is-locked{overflow:hidden}

/* Lenis smooth-scroll requirements (the library does not inject these itself) */
html.lenis,html.lenis body{height:auto}
.lenis.lenis-smooth{scroll-behavior:auto!important}
.lenis.lenis-smooth [data-lenis-prevent]{overscroll-behavior:contain}
.lenis.lenis-stopped{overflow:hidden}
.lenis.lenis-smooth iframe{pointer-events:none}

img{max-width:100%;display:block}
a{color:inherit;text-decoration:none}
button,input,select,textarea{font:inherit;color:inherit}
button{background:none;border:0;cursor:pointer}
ul{list-style:none}
::selection{background:var(--green);color:#fff}

.container{width:100%;max-width:var(--container);margin-inline:auto;padding-inline:var(--pad)}
.section{padding-block:var(--sec)}
.ic{width:20px;height:20px;flex:none}
.ic--xs{width:13px;height:13px}

h1,h2,h3,h4,h5,h6{font-family:var(--ff-display);line-height:1.2;font-weight:700;color:var(--ink)}

/* section heading: title left, tabs/controls right — as on the reference */
.shead{display:flex;justify-content:space-between;align-items:center;gap:22px;
  margin-bottom:22px;flex-wrap:wrap}
.shead h2{font-size:clamp(1.35rem,2.1vw,1.75rem)}
/* modifier for a heading that stands alone, with no tabs or arrows beside it */
.shead--center{justify-content:center;text-align:center}

.price{display:flex;align-items:baseline;gap:7px;font-family:var(--ff-body)}
.price b{font-size:1rem;font-weight:700;color:var(--red)}
.price s{font-size:.86rem;color:var(--ink-30);font-weight:400}

.link-arrow{display:inline-flex;align-items:center;gap:7px;font-weight:700;font-size:.86rem;color:var(--green)}
.link-arrow .ic{width:15px;height:15px;transition:transform .3s}
.link-arrow:hover .ic{transform:translateX(4px)}

/* ---------- 3. BUTTONS ---------- */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:8px;
  background:var(--ink);color:#fff;font-family:var(--ff-body);font-weight:700;font-size:.86rem;
  padding:11px 24px;border-radius:var(--r-pill);white-space:nowrap;
  transition:background .28s,color .28s,transform .28s;
}
.btn:hover{background:var(--green);transform:translateY(-1px)}
.btn .ic{width:15px;height:15px;transition:transform .3s}
.btn:hover .ic{transform:translateX(3px)}
.btn--green{background:var(--green)}
.btn--green:hover{background:var(--ink)}
.btn--sm{padding:9px 18px;font-size:.8rem}

/* ---------- PRELOADER / CURSOR / PROGRESS ---------- */
.preloader{position:fixed;inset:0;z-index:9999;background:#fff;display:grid;place-items:center}
.preloader__inner{width:min(320px,72vw);text-align:center}
.preloader__logo{width:180px;margin:0 auto 24px}
.preloader__bar{height:3px;background:#EDEDED;border-radius:3px;overflow:hidden}
.preloader__bar span{display:block;height:100%;width:0;background:var(--green);border-radius:3px}
.preloader__meta{display:flex;justify-content:space-between;margin-top:11px;font-size:.72rem;
  font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--ink-30)}
.preloader__curtain{position:absolute;inset:0;background:var(--green);transform:scaleY(0);transform-origin:bottom}

/* The custom cursor is retired. Its markup is still in header.php, but with no
   script positioning it the dot and ring would sit in the top-left corner, so
   hide it outright. The rules below are kept for reference only. */
.cursor{display:none}
.cursor--legacy{position:fixed;top:0;left:0;z-index:9998;pointer-events:none}
.cursor__dot,.cursor__ring{position:absolute;top:0;left:0;border-radius:50%;transform:translate(-50%,-50%)}
.cursor__dot{width:5px;height:5px;background:var(--green)}
.cursor__ring{width:30px;height:30px;border:1.5px solid rgba(38,156,83,.4);transition:width .3s,height .3s,background .3s}
.cursor.is-link .cursor__ring{width:52px;height:52px;background:rgba(38,156,83,.12);border-color:transparent}
.cursor.is-link .cursor__dot{opacity:0}
@media (hover:none),(pointer:coarse){.cursor{display:none}}

.scroll-progress{position:fixed;top:0;left:0;right:0;height:3px;z-index:900}
/* full width from the start, revealed by a scaleX the compositor owns —
   growing it by `width` instead would relayout and repaint on every frame */
.scroll-progress span{display:block;height:100%;width:100%;background:var(--orange);
  transform:scaleX(0);transform-origin:0 50%;will-change:transform}

/* ---------- 4. HEADER ---------- */
/* announcement ticker — the top-most strip, scrolls away with the page.
   Three identical groups ride in one flex row; sliding the row by exactly one
   group (-33.333%) lands back on a matching frame, so the loop is invisible. */
.ticker{background:var(--green);color:#fff;overflow:hidden}
.ticker__row{display:flex;width:max-content;animation:ticker-slide 38s linear infinite}
/* let a reader stop a message to finish it */
.ticker:hover .ticker__row{animation-play-state:paused}
.ticker__group{display:flex;align-items:center;flex:none}
.ticker__group li{position:relative;display:flex;align-items:center;gap:9px;white-space:nowrap;
  padding:9px clamp(20px,3vw,38px);font-size:.78rem;font-weight:700;letter-spacing:.01em}
/* dot separator sits on the shared edge between two messages */
.ticker__group li::after{content:"";position:absolute;right:0;top:50%;width:5px;height:5px;
  margin-top:-2.5px;border-radius:50%;background:rgba(255,255,255,.45)}
.ticker .ic{width:16px;height:16px;opacity:.92}
@keyframes ticker-slide{to{transform:translateX(-33.3333%)}}

/* Two white bars stacked read as one block, so the rows are separated by tone:
   the upper stays pure white, the nav row below takes a faint warm tint. */
.header__upper{background:#fff;color:var(--ink);border-bottom:1px solid var(--line)}
/* logo | search (fills the middle) | hotline + account icons pinned right */
.header__upper-in{display:flex;align-items:center;gap:clamp(16px,2.6vw,36px);padding-block:16px}
/* hotline and the account/cart icons travel together as one right-hand block */
.header__util{display:flex;align-items:center;gap:clamp(10px,1.6vw,20px);flex:none;margin-left:auto}
.brand{flex:none;display:flex;align-items:center}
/* logo.png ships on an opaque white plate — multiply drops that plate into the
   tinted bar instead of showing as a white box. The artwork also sits ~8px
   inside its own canvas, so pull it back to line up with the row below. */
.brand img{width:clamp(104px,11vw,138px);margin-left:-8px;mix-blend-mode:multiply}

.search{flex:1;min-width:0;display:flex;align-items:stretch;background:#fff;
  border:1px solid var(--line-2);border-radius:var(--r-pill);padding:3px;
  transition:border-color .25s,box-shadow .25s}
.search:focus-within{border-color:var(--green);box-shadow:0 0 0 3px rgba(38,156,83,.12)}

.search input{flex:1;border:0;outline:0;background:none;font-size:.88rem;padding:9px 16px;min-width:0}
.search input::placeholder{color:var(--ink-30)}
.search__btn{flex:none;width:38px;height:38px;border-radius:50%;background:var(--orange);color:#fff;
  display:grid;place-items:center;align-self:center;transition:background .28s}
.search__btn:hover{background:var(--orange-dark)}
.search__btn .ic{width:17px;height:17px}

.hotline{display:flex;align-items:center;gap:10px;flex:none;color:var(--ink)}
.hotline__ic{width:38px;height:38px;border-radius:50%;background:var(--green-soft);color:var(--green);
  display:grid;place-items:center;transition:background .25s,color .25s}
.hotline:hover .hotline__ic{background:var(--green);color:#fff}
.hotline__txt b{display:block;font-family:var(--ff-display);font-size:.98rem;line-height:1.15}
.hotline__txt small{font-size:.7rem;color:var(--ink-50)}

/* lower: faintly tinted bar carrying the nav, centred in the row */
/* pinned to the top for the whole page — it never hides on scroll */
.header{position:sticky;top:0;z-index:50;background:#F7F8F6;border-bottom:1px solid var(--line);
  transition:box-shadow .3s}
.header.is-stuck{box-shadow:0 4px 18px -12px rgba(0,0,0,.3)}
/* the burger keeps its own auto margin below 1024px, which overrides this */
.header__in{display:flex;align-items:center;justify-content:center;gap:18px;min-height:56px}

.nav{display:flex;align-items:center;gap:2px}
.nav__item>a{display:flex;align-items:center;gap:5px;padding:12px 14px;font-size:.88rem;font-weight:700;color:var(--ink);
  transition:color .25s}
.nav__item>a:hover,.nav__item.is-active>a{color:var(--green)}
.nav__item .ic--xs{transform:rotate(90deg);color:var(--ink-30)}

/* single-level dropdown — a plain list, no mega panel */
.has-drop{position:relative}
.has-drop>a .ic--xs{transition:transform .28s}
.has-drop:hover>a .ic--xs{transform:rotate(-90deg)}
.nav__drop{position:absolute;top:100%;left:0;min-width:230px;background:#fff;
  border:1px solid var(--line);border-radius:var(--r-sm);box-shadow:var(--shadow-md);padding:6px;z-index:40;
  opacity:0;visibility:hidden;transform:translateY(-8px);
  transition:opacity .24s,transform .28s cubic-bezier(.2,.8,.2,1),visibility .24s}
/* focus-within keeps it reachable by keyboard, not just hover */
.has-drop:hover .nav__drop,.has-drop:focus-within .nav__drop{opacity:1;visibility:visible;transform:translateY(0)}
.nav__drop a{display:block;padding:8px 13px;border-radius:var(--r-xs);font-size:.85rem;font-weight:400;
  color:var(--ink-70);white-space:nowrap;transition:background .2s,color .2s,transform .25s}
.nav__drop a:hover{background:var(--green-soft);color:var(--green);transform:translateX(3px)}

.header__actions{display:flex;align-items:center;gap:2px}
.hact{position:relative;display:flex;align-items:center;justify-content:center;width:46px;height:46px;
  border-radius:var(--r-sm);color:var(--ink-70);transition:background .22s,color .22s}
.hact:hover{background:var(--green-soft);color:var(--green)}
.hact .ic{width:26px;height:26px}
.badge{position:absolute;top:2px;right:2px;min-width:18px;height:18px;padding:0 5px;background:var(--green);
  color:#fff;border-radius:var(--r-pill);font-size:.65rem;font-weight:700;display:grid;place-items:center;font-style:normal}
.burger{display:none;flex-direction:column;gap:4px;padding:10px}
.burger span{width:20px;height:2px;background:var(--ink);border-radius:2px;transition:transform .3s,opacity .2s}
.burger.is-open span:nth-child(1){transform:translateY(6px) rotate(45deg)}
.burger.is-open span:nth-child(2){opacity:0}
.burger.is-open span:nth-child(3){transform:translateY(-6px) rotate(-45deg)}

/* mobile drawer */
.drawer{position:fixed;inset:0;z-index:70;visibility:hidden}
.drawer.is-open{visibility:visible}
.drawer::before{content:"";position:absolute;inset:0;background:rgba(0,0,0,.45);opacity:0;transition:opacity .35s}
.drawer.is-open::before{opacity:1}
.drawer__panel{position:absolute;top:0;right:0;bottom:0;width:min(340px,88vw);background:#fff;
  padding:24px 22px calc(24px + env(safe-area-inset-bottom));
  display:flex;flex-direction:column;transform:translateX(100%);
  transition:transform .45s cubic-bezier(.65,0,.35,1);
  overflow-y:auto;overflow-x:hidden;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;
  box-shadow:-18px 0 50px -24px rgba(0,0,0,.4)}
.drawer.is-open .drawer__panel{transform:translateX(0)}
/* head: soft green wash behind the logo, with a close control */
.drawer__head{display:flex;align-items:center;justify-content:space-between;gap:14px;
  margin:-24px -22px 18px;padding:20px 22px;
  background:linear-gradient(135deg,var(--green-soft),#F4FAF6 60%,#fff);
  border-bottom:1px solid var(--line)}
.drawer__logo{width:118px;mix-blend-mode:multiply}
.drawer__close{position:relative;width:38px;height:38px;border-radius:50%;background:#fff;flex:none;
  border:1px solid var(--line-2);transition:background .25s,border-color .25s,transform .3s}
.drawer__close:hover{background:var(--green);border-color:var(--green);transform:rotate(90deg)}
.drawer__close span{position:absolute;top:50%;left:50%;width:14px;height:2px;border-radius:2px;
  background:var(--ink);transition:background .25s}
.drawer__close span:nth-child(1){transform:translate(-50%,-50%) rotate(45deg)}
.drawer__close span:nth-child(2){transform:translate(-50%,-50%) rotate(-45deg)}
.drawer__close:hover span{background:#fff}

.drawer__nav{display:flex;flex-direction:column;gap:2px}
.drawer__nav > a{position:relative;padding:13px 14px;border-radius:var(--r-sm);font-weight:700;font-size:.95rem;
  transition:background .22s,color .22s,padding-left .25s}
.drawer__nav > a::before{content:"";position:absolute;left:0;top:50%;width:3px;height:0;border-radius:3px;
  background:var(--green);transform:translateY(-50%);transition:height .28s}
.drawer__nav > a:hover{background:var(--green-soft);color:var(--green);padding-left:18px}
.drawer__nav > a:hover::before{height:18px}

/* The accordion that used to live here is gone. A category in the drawer was
   a .drawer__group — a toggle button that expanded a .drawer__sub list of
   that category's products — and it is now a plain link straight to the
   category, like every other row. buildDrawerNav() no longer creates any of
   those elements, so their rules could never match anything again. */

/* foot: call card, utility links, socials */
.drawer__foot{margin-top:auto;padding-top:22px}
.drawer__call{display:flex;align-items:center;gap:12px;padding:12px 14px;border-radius:var(--r-sm);
  background:var(--green);color:#fff;transition:background .25s}
.drawer__call:hover{background:var(--ink)}
.drawer__call-ic{width:38px;height:38px;border-radius:50%;background:rgba(255,255,255,.2);
  display:grid;place-items:center;flex:none}
.drawer__call small{display:block;font-size:.7rem;opacity:.85}
.drawer__call b{font-family:var(--ff-display);font-size:1rem}
.drawer__social{display:flex;gap:7px;flex-wrap:wrap;margin-top:14px}
.drawer__social a{border:1px solid var(--line-2);border-radius:var(--r-pill);padding:6px 13px;
  font-size:.75rem;font-weight:700;color:var(--ink-70);transition:background .25s,color .25s,border-color .25s}
.drawer__social a:hover{background:var(--green);color:#fff;border-color:var(--green)}

/* ---------- 5. CATEGORY TILES ---------- */
.catstrip{padding-block:clamp(20px,2.6vw,34px)}
/* The category strip was a grid of exactly eight columns, from when there
   were exactly eight categories. Categories are managed in the admin, so
   that number is whatever the shop decides — at seven the eighth column
   stayed empty and the whole row sat pushed to the left with a hole beside
   it.

   Flex instead of grid, for one reason: an incomplete row centres itself.
   A grid places items into fixed columns starting at the left, so a row
   with three tiles in it leaves a gap on the right no matter what; flex
   with justify-content:center puts the gap on both sides, which is what
   the eye reads as deliberate.

   The basis is an eighth of the row, so eight still fit across; flex-grow
   lets a smaller number widen to fill the row evenly instead of huddling
   in the middle at eighth-width. max-width stops two lonely categories
   from becoming two enormous slabs. */
.catgrid{--cgap:clamp(10px,1.2vw,16px);
  display:flex;flex-wrap:wrap;justify-content:center;gap:var(--cgap)}
.catcard{flex:1 1 calc((100% - 7 * var(--cgap)) / 8);max-width:260px;
  background:var(--tint,var(--green-soft));border-radius:var(--r-lg);padding:22px 12px 18px;
  text-align:center;position:relative;overflow:hidden;
  transition:transform .4s cubic-bezier(.2,.8,.2,1),box-shadow .4s}
.catcard::after{content:"";position:absolute;left:50%;bottom:-40%;width:130%;aspect-ratio:1;
  border-radius:50%;background:rgba(255,255,255,.55);transform:translate(-50%,0) scale(.6);
  opacity:0;transition:transform .55s cubic-bezier(.2,.8,.2,1),opacity .45s}
.catcard:hover{transform:translateY(-6px);box-shadow:var(--shadow-md)}
.catcard:hover::after{opacity:1;transform:translate(-50%,0) scale(1)}
.catcard figure{position:relative;z-index:1;width:clamp(64px,5.4vw,80px);aspect-ratio:1;border-radius:50%;
  overflow:hidden;margin:0 auto 13px;border:3px solid #fff;box-shadow:var(--shadow-sm)}
.catcard img{width:100%;height:100%;object-fit:cover;transition:transform .55s cubic-bezier(.2,.8,.2,1)}
.catcard:hover img{transform:scale(1.14)}
.catcard b{position:relative;z-index:1;display:block;font-family:var(--ff-display);font-size:.9rem;
  font-weight:700;line-height:1.25;margin-bottom:2px}
.catcard small{position:relative;z-index:1;font-size:.74rem;color:var(--ink-50)}

/* ---------- 6. BANNER CAROUSEL ---------- */
/* Box ratio matches the artwork at each breakpoint, so `cover` never crops:
   1600x492 on desktop, 390x429 below 768px. */
/* full-bleed: no container padding, no rounded corners */
.hbanner{padding-block:0}
.hbanner__box{position:relative;overflow:hidden;background:var(--tint);
  aspect-ratio:1600/492}
/* The slides sit side by side in one flex row and the row slides.

   The whole transition lives in this one `transition` — the only thing that
   ever moves is the track, and JS only ever sets it to exactly
   translateX(-index * 100%). That is deliberate: the previous version tweened
   each <img> individually and left one behind at -5%, which is what put a bare
   95px strip down the side of the banner. An image here is never transformed,
   so it cannot be stranded off its own box. */
.hbanner__track{position:absolute;inset:0;display:flex;will-change:transform;
  transition:transform .6s cubic-bezier(.4,0,.2,1)}
/* used for the seamless wrap: reposition with no transition, then resume */
.hbanner__track.is-jump{transition:none}
.hbanner__slide{position:relative;flex:0 0 100%;height:100%}
.hbanner__slide a,.hbanner__slide picture{display:block;width:100%;height:100%}
/* the image must always fill its slide exactly; nothing may offset it */
.hbanner__slide img{width:100%;height:100%;object-fit:cover;transform:none}
@media (prefers-reduced-motion:reduce){.hbanner__track{transition:none}}

.hbanner__nav{position:absolute;top:50%;transform:translateY(-50%);z-index:3;width:42px;height:42px;
  border-radius:50%;background:rgba(255,255,255,.85);color:var(--ink);display:grid;place-items:center;
  box-shadow:var(--shadow-md);opacity:0;transition:opacity .3s,background .25s,transform .25s}
.hbanner__box:hover .hbanner__nav{opacity:1}
.hbanner__nav:hover{background:var(--green);color:#fff;transform:translateY(-50%) scale(1.08)}
.hbanner__nav--prev{left:14px}
.hbanner__nav--next{right:14px}
/* eyebrow pill on the delivery banner */
.promo__eyebrow{display:inline-block;background:var(--red);color:#fff;font-size:.64rem;font-weight:700;
  letter-spacing:.1em;text-transform:uppercase;padding:5px 11px;border-radius:var(--r-pill);margin-bottom:14px}
/* ---------- 7. PRODUCT CARD ---------- */
.tabs{display:flex;gap:2px;flex-wrap:wrap}
.tab{padding:7px 14px;font-size:.85rem;font-weight:700;color:var(--ink-50);position:relative;transition:color .25s}
.tab::after{content:"";position:absolute;left:14px;right:14px;bottom:0;height:2px;background:var(--green);
  transform:scaleX(0);transition:transform .3s}
.tab:hover{color:var(--ink)}
.tab.is-active{color:var(--green)}
.tab.is-active::after{transform:scaleX(1)}

/* The phone-width stand-in for .tabs — see the note beside the markup in
   index.php. Hidden here and switched on with .tabs off in the 768px block;
   the pair is never both visible and never both hidden. */
.tabsel{display:none;position:relative;align-items:center;width:100%}
.tabsel select{appearance:none;-webkit-appearance:none;width:100%;
  padding:11px 38px 11px 16px;font-size:.88rem;font-weight:700;color:var(--ink);
  border:1px solid var(--line-2);border-radius:var(--r-pill);background:var(--card,#fff);cursor:pointer}
.tabsel select:focus{outline:none;border-color:var(--green);box-shadow:0 0 0 3px var(--wash,rgba(38,156,83,.12))}
.tabsel .ic{position:absolute;right:15px;width:15px;height:15px;
  transform:rotate(90deg);pointer-events:none;color:var(--ink-50)}

.carousel-nav{display:flex;gap:7px}
.carousel-nav button{width:36px;height:36px;border-radius:50%;border:1px solid var(--line-2);background:#fff;
  display:grid;place-items:center;color:var(--ink-70);transition:background .25s,color .25s,border-color .25s}
.carousel-nav button:hover{background:var(--green);color:#fff;border-color:var(--green)}

.shopgrid{display:grid;grid-template-columns:repeat(5,1fr);gap:clamp(10px,1.2vw,16px)}
.rail{display:flex;gap:clamp(10px,1.2vw,16px);overflow-x:auto;scroll-snap-type:x mandatory;padding-bottom:8px;
  scrollbar-width:none}
.rail::-webkit-scrollbar{display:none}
.rail{--gap:clamp(10px,1.2vw,16px)}
.rail .prod{flex:0 0 calc((100% - 4 * var(--gap)) / 5);scroll-snap-align:start}

.prod{background:#fff;border:1px solid var(--line);border-radius:var(--r-sm);overflow:hidden;
  display:flex;flex-direction:column;transition:border-color .3s,box-shadow .3s,transform .3s}
.prod.is-hidden{display:none}
.prod:hover{border-color:transparent;box-shadow:var(--shadow-md);transform:translateY(-3px)}
.prod__media{position:relative;aspect-ratio:1/.92;overflow:hidden;background:var(--tint)}
.prod__media img{width:100%;height:100%;object-fit:cover;transition:transform .6s}
.prod:hover .prod__media img{transform:scale(1.07)}
.off{position:absolute;top:9px;left:9px;background:var(--green);color:#fff;font-size:.63rem;font-weight:700;
  padding:3px 8px;border-radius:var(--r-xs);letter-spacing:.02em}
.off--hot{background:var(--red)}
/* A named size container, so the action row below can ask how wide the card
   actually is rather than how wide the screen is. The same card is a fifth of
   a rail on desktop and half of one on a phone. */
.prod__body{padding:12px 13px 13px;display:flex;flex-direction:column;flex:1;
  container:prodbody / inline-size}
.prod__cat{font-size:.72rem;color:var(--ink-30);margin-bottom:3px}
/* one line on desktop, two on mobile — anything longer ends in an ellipsis,
   so the cards in a row keep the same rhythm however long the name is */
.prod h4{font-size:.88rem;font-weight:700;line-height:1.35;margin-bottom:7px;
  display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:1;line-clamp:1;
  overflow:hidden}
.prod h4 a:hover{color:var(--green)}
/* variation pills — selecting one swaps the price below */
.prod__vars{display:flex;flex-wrap:wrap;gap:5px;margin-bottom:12px}
.prod__vars button{padding:4px 10px;border:1px solid var(--line-2);border-radius:var(--r-pill);
  font-size:.72rem;font-weight:700;color:var(--ink-50);white-space:nowrap;
  transition:border-color .2s,background .2s,color .2s}
.prod__vars button:hover{border-color:var(--green);color:var(--green)}
.prod__vars button.is-active{background:var(--green);border-color:var(--green);color:#fff}

/* The price row and the action row sit together at the foot of the card, so
   the buttons line up across a row however tall the name or the size pills
   above them are.

   The `margin-top:auto` that does that has to sit on whichever of the two
   comes first. It used to be on .prod__foot alone, which was fine while every
   card had a price — but a card with no price does not print .prod__foot at
   all, and its button then rode up under the size pills while the priced card
   beside it kept its button at the bottom. The `~` rule hands the auto margin
   back to .prod__foot whenever it is there. */
.prod__foot{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-top:auto;
  margin-bottom:11px}
/* full-width outlined button that fills on hover */
.prod__add{display:flex;align-items:center;justify-content:center;gap:7px;width:100%;
  padding:9px 12px;border:1.5px solid var(--green);border-radius:var(--r-pill);
  background:transparent;color:var(--green);font-family:var(--ff-body);font-weight:700;font-size:.78rem;
  letter-spacing:.01em;transition:background .25s,color .25s,border-color .25s}
.prod__add .ic{width:15px;height:15px}
.prod__add:hover{background:var(--green);color:#fff}
.prod__add:active{background:var(--green-dark);border-color:var(--green-dark)}

/* The card's action row. Usually one control, occasionally two — an
   out-of-stock product shows the greyed button and a way through to the
   product beside it. flex:1 1 0 means a lone control fills the row and a
   pair splits it evenly; min-width:0 because a flex item will not shrink
   below its content width by default, which would push a pair wider than
   the card in a narrow column. */
.prod__actions{display:flex;align-items:stretch;gap:8px;margin-top:auto}
/* .prod__foot already carries the auto margin when it is present — see the
   note there. Two auto margins in one flex column would split the free space
   between them and open a gap between the price and the button. */
.prod__foot ~ .prod__actions{margin-top:0}
.prod__actions>*{flex:1 1 0;min-width:0}
/* .prod__add sets display:flex, which outranks the display:none a plain
   [hidden] would give it — so a hidden control would still be laid out.
   The script toggles `hidden` as the size changes, and this is what makes
   that actually hide anything. */
.prod__actions>[hidden]{display:none}

/* Muted rather than green: it goes somewhere to read, it does not buy
   anything, and it should not read as the main action on the card. */
.prod__add--info{border-color:var(--line-2);color:var(--ink-50);white-space:nowrap}
.prod__add--info:hover{background:var(--tint);border-color:var(--line-2);color:var(--ink)}

/* One control when two will not fit.
   "Out of stock" beside "View details" needs roughly 230px. On a narrow card
   each got half of ~120px, so "Out of stock" wrapped onto three lines and the
   pill ballooned into a tall oval. That one tall card then broke every card
   around it: a grid row stretches to its tallest card, so the neighbour's
   price no longer lined up, and a rail stretches every card to its tallest,
   which opened an empty gap above the price on all of them.

   The disabled button is the one to lose. It only repeats what the corner
   badge and the struck-through size pills already say, while View details is
   the one thing on the card that still goes somewhere. It keys on .is-sold on
   the button, not the card, because main.js sets that per size: an in-stock
   product with a sold-out size selected lands in the same state. When a size
   that can be bought is picked, the class goes and Add to Cart comes back. */
@container prodbody (max-width:230px){
  .prod__actions>.prod__add.is-sold{display:none}
}
/* once the line is in the basket the Add button hands over to this stepper */
.prod__qty{display:none;align-items:center;gap:8px;width:100%;
  padding:7px 10px;border:1.5px solid var(--green);border-radius:var(--r-pill);
  background:var(--green-soft)}
/* Once the line is in the basket the stepper replaces the Add button — but
   only that button. This was `.prod.has-qty .prod__add`, which now also
   matches the View details link sharing the row with it, and would take the
   way into the product away the moment somebody added one to the basket. */
.prod.has-qty .prod__add.add-cart{display:none}
.prod.has-qty .prod__qty{display:flex}
.prod__qty button{flex:0 0 auto;width:22px;height:22px;border-radius:50%;display:grid;place-items:center;
  background:#fff;color:var(--green);font-size:1rem;line-height:1;font-weight:700;
  transition:background .2s,color .2s}
.prod__qty button:hover{background:var(--green);color:#fff}
.prod__qty b{flex:1;text-align:center;font-size:.8rem;font-weight:700;line-height:1;color:var(--green)}

/* ---------- 8. FEATURED PASTEL TILES ---------- */
.ads{padding-block:clamp(16px,2vw,26px)}
/* The row fits however many featured cards are published — three or four
   sit comfortably; a fourth used to wrap onto a row of its own. */
.ads__grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));
  gap:clamp(12px,1.6vw,22px)}
/* The tile is the artwork and nothing else.

   It used to be a two-part card: a text panel over the left 62% and the
   photograph fading in from the right under a mask. That suits a plain
   product photograph. It fights a finished banner that already carries its
   own headline and button, which is what these are — the mask cut the
   design in half and the panel printed a second title on top of the first.

   So: no text layer, no mask, no cropping. The image sets the height, which
   means three banners exported at one size line up on their own, and one
   exported at a different size is visibly the odd one rather than being
   silently cropped to fit. align-items:start keeps each tile its own height
   instead of stretching the short one and leaving a band of background. */
.ad{position:relative;border-radius:var(--r-lg);overflow:hidden;display:block;
  line-height:0;
  /* A fixed shape, so three banners line up whatever sizes they were saved
     at. Without it the tile takes the image's own height and a row of three
     comes out 314px, 558px and 271px tall — which is what happened the first
     time, with three stock photos standing in.
     2:1 matches the artwork these are made at; export at 1040x520 and nothing
     is cropped at all. */
  /*aspect-ratio:2 / 1*/}
/* the tint still shows for the moment before the image arrives, and behind
   one that never does */
.ad--pink{background:#FBE4EC}
.ad--amber{background:#FBE0AE}
.ad--mint{background:#DFF1E3}
.ad--rust{background:#F7DCCB}
.ad__art{position:absolute;inset:0;overflow:hidden}
/* cover, not contain: a banner saved at the right shape fills the tile edge
   to edge, and one saved slightly off loses a sliver of its margin rather
   than sitting in a letterbox of pastel. */
.ad__art img{width:100%;height:100%;object-fit:cover;display:block;transition:transform .7s}
/* No hover zoom either. These tiles are finished banners, and nudging one
   up by 3% crops a sliver off all four edges - which on artwork with a
   button near the bottom is exactly where it is least welcome. */

/* ---------- 10. WIDE CTA BANNER ---------- */
/* The band is the artwork, full width, nothing over it.

   It was a two-part panel: text across the left 60%, photograph filling
   the right 44% under a mask that faded it in. Good for a photograph,
   wrong for a finished banner that already carries its heading, its line
   of copy and its button — the panel printed a second headline over the
   first and the design was squeezed into under half the width.

   No min-height and no cropping: the image sets the height, so a banner
   made at any width lands at its true proportions. The tint stays for the
   moment before it loads. */
.ctaband{position:relative;display:block;border-radius:var(--r-lg);overflow:hidden;
  background:#FBD9A0;line-height:0;margin-block:clamp(16px,2vw,28px)}
.ctaband img{width:100%;height:auto;display:block}

/* ---------- 11. VIDEOS ---------- */
.rail--videos .vid{flex:0 0 calc((100% - 3 * var(--gap)) / 4);scroll-snap-align:start}
/* A column, so the caption block can fill whatever height the row takes.
   Without this the card is a plain block: the grid stretches it to the
   tallest card in the row, the caption stays at the top, and the leftover
   space collects under the shortest ones. */
.vid{background:#fff;border:1px solid var(--line);border-radius:var(--r-sm);overflow:hidden;
  display:flex;flex-direction:column;
  transition:border-color .3s,box-shadow .3s,transform .3s}
.vid:hover{border-color:transparent;box-shadow:var(--shadow-md);transform:translateY(-3px)}
.vid__media{position:relative;aspect-ratio:16/9;overflow:hidden;background:#000}
.vid__media img{width:100%;height:100%;object-fit:cover;transition:transform .6s,opacity .3s}
.vid:hover .vid__media img{transform:scale(1.06);opacity:.82}
/* the iframe swapped in on click fills the same box */
.vid__media iframe{position:absolute;inset:0;width:100%;height:100%;border:0}
.vid__play{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);
  width:52px;height:52px;border-radius:50%;background:rgba(255,255,255,.92);color:var(--green);
  display:grid;place-items:center;box-shadow:0 6px 20px -6px rgba(0,0,0,.5);
  transition:transform .3s cubic-bezier(.34,1.56,.64,1),background .25s,color .25s}
.vid__play .ic{width:20px;height:20px;margin-left:2px}
.vid:hover .vid__play{transform:translate(-50%,-50%) scale(1.1)}
.vid__play:hover{background:var(--green);color:#fff}
.vid__body{padding:13px 14px 15px;flex:1;display:flex;flex-direction:column}
/* Two lines of title on every card, whether the title needs them or not,
   so the label underneath sits on the same line right across a row. A
   longer title ends in an ellipsis rather than pushing the card taller. */
.vid__body h4{font-size:.92rem;font-weight:700;line-height:1.35;margin-bottom:3px;
  display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2;
  overflow:hidden;min-height:calc(2 * 1.35em)}
/* the label sits against the bottom of the card, however tall the row is */
.vid__body small{font-size:.75rem;color:var(--ink-50);margin-top:auto}
/* the media box must not be squashed when the row is taller than the card */
.vid__media{flex:none}
/* ---------- 12. NEWS ---------- */
.posts{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(14px,1.8vw,24px)}
.post{border:1px solid var(--line);border-radius:var(--r-sm);overflow:hidden;background:#fff;
  transition:border-color .3s,box-shadow .3s,transform .3s}
.post:hover{border-color:transparent;box-shadow:var(--shadow-md);transform:translateY(-3px)}
/* display:block matters — this is an <a>, and an inline box ignores aspect-ratio */
.post__media{display:block;position:relative;aspect-ratio:16/10;overflow:hidden;background:var(--tint)}
.post__media img{width:100%;height:100%;object-fit:cover;transition:transform .6s}
.post:hover .post__media img{transform:scale(1.06)}
.post__cat{position:absolute;top:12px;left:12px;background:var(--green);color:#fff;font-size:.63rem;font-weight:700;
  letter-spacing:.07em;text-transform:uppercase;padding:4px 10px;border-radius:var(--r-xs)}
.post__body{padding:18px}
.post__body small{font-size:.74rem;color:var(--ink-30)}
.post__body h4{font-size:1.02rem;margin:7px 0 7px;line-height:1.35}
.post__body p{font-size:.85rem;color:var(--ink-70);margin-bottom:12px}

/* ---------- 13. HIGHLIGHTS ---------- */
.highlights{border-top:1px solid var(--line);background:var(--bg-2)}
.highlights__grid{display:grid;grid-template-columns:repeat(4,1fr);gap:clamp(16px,2.2vw,30px);
  padding-block:clamp(26px,3vw,42px)}
.hl{display:flex;align-items:center;gap:13px}
.hl__ic{flex:none;width:46px;height:46px;border-radius:50%;background:var(--green-soft);color:var(--green);
  display:grid;place-items:center;transition:background .28s,color .28s,transform .3s}
.hl:hover .hl__ic{background:var(--green);color:#fff;transform:translateY(-2px)}
.hl__ic .ic{width:22px;height:22px}
.hl__txt b{display:block;font-family:var(--ff-display);font-size:.96rem;margin-bottom:2px}
.hl__txt span{display:block;font-size:.8rem;color:var(--ink-50);line-height:1.4}

/* ---------- 14. FOOTER ---------- */
.footer{background:#12261A;color:rgba(255,255,255,.66);position:relative;overflow:hidden}
.footer__top{padding-block:clamp(40px,5vw,66px) clamp(26px,3vw,40px)}
.footer__grid{display:grid;grid-template-columns:1.5fr repeat(4,1fr);gap:clamp(20px,2.6vw,40px)}
.footer__brand img{width:146px;margin-bottom:16px;background:#fff;padding:8px 12px;border-radius:var(--r-sm)}
.footer__brand p{font-size:.86rem;max-width:32ch;margin-bottom:18px}
.socials{display:flex;gap:8px;flex-wrap:wrap}
.socials a{border:1px solid rgba(255,255,255,.2);border-radius:var(--r-pill);padding:6px 14px;font-size:.75rem;
  font-weight:700;transition:background .25s,color .25s,border-color .25s}
.socials a:hover{background:var(--green);color:#fff;border-color:var(--green)}
.footer__col h6{color:#fff;font-family:var(--ff-body);font-size:.74rem;letter-spacing:.11em;text-transform:uppercase;margin-bottom:14px}
.footer__col a,.footer__col p{display:flex;align-items:flex-start;gap:7px;padding:4px 0;font-size:.85rem;
  overflow-wrap:anywhere;transition:color .22s,transform .28s}
.footer__col a:hover{color:var(--green);transform:translateX(3px)}
.footer__col .ic{width:15px;height:15px;flex:none;margin-top:4px;color:var(--green)}
.footer__bar{border-top:1px solid rgba(255,255,255,.12);padding-block:16px}
.footer__bar-in{display:flex;align-items:center;justify-content:space-between;gap:10px 22px;flex-wrap:wrap;font-size:.78rem}
/* legal links sit opposite the copyright, and centre together on small screens */
.footer__legal{display:flex;gap:6px 18px;flex-wrap:wrap}
.footer__legal a{transition:color .22s}
.footer__legal a:hover{color:var(--green)}
@media (max-width:760px){
  .footer__bar-in{justify-content:center;text-align:center}
  .footer__legal{justify-content:center}
}

/* ---------- CART PANEL ---------- */
.cart{position:fixed;inset:0;z-index:90;visibility:hidden}
.cart.is-open{visibility:visible}
.cart::before{content:"";position:absolute;inset:0;background:rgba(0,0,0,.45);opacity:0;transition:opacity .35s}
.cart.is-open::before{opacity:1}
.cart__panel{position:absolute;top:0;right:0;bottom:0;width:min(390px,92vw);background:#fff;
  display:flex;flex-direction:column;transform:translateX(100%);
  transition:transform .45s cubic-bezier(.65,0,.35,1);box-shadow:-18px 0 50px -24px rgba(0,0,0,.4)}
.cart.is-open .cart__panel{transform:translateX(0)}

.cart__head{display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:20px 22px;border-bottom:1px solid var(--line)}
.cart__head h3{font-size:1.1rem;display:flex;align-items:center;gap:8px}
.cart__head em{font-style:normal;background:var(--green);color:#fff;font-family:var(--ff-body);
  font-size:.7rem;font-weight:700;padding:2px 9px;border-radius:var(--r-pill)}
.cart__close{position:relative;width:34px;height:34px;border-radius:50%;background:var(--bg-2);flex:none;
  transition:background .25s,transform .3s}
.cart__close:hover{background:var(--green);transform:rotate(90deg)}
.cart__close span{position:absolute;top:50%;left:50%;width:13px;height:2px;border-radius:2px;
  background:var(--ink);transition:background .25s}
.cart__close span:nth-child(1){transform:translate(-50%,-50%) rotate(45deg)}
.cart__close span:nth-child(2){transform:translate(-50%,-50%) rotate(-45deg)}
.cart__close:hover span{background:#fff}

.cart__body{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;padding:16px 22px}
.cart__items{display:flex;flex-direction:column;gap:12px}
.citem{display:flex;gap:12px;padding-bottom:12px;border-bottom:1px solid var(--line)}
.citem:last-child{border-bottom:0}
.citem__img{width:64px;height:64px;border-radius:var(--r-xs);overflow:hidden;background:var(--tint);flex:none}
.citem__img img{width:100%;height:100%;object-fit:cover}
.citem__main{flex:1;min-width:0}
.citem__name{display:block;font-size:.86rem;font-weight:700;line-height:1.35;margin-bottom:2px}
.citem__var{font-size:.74rem;color:var(--ink-50)}
.citem__bottom{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-top:8px}
.citem__price{font-size:.9rem;font-weight:700;color:var(--red)}
.qty{display:flex;align-items:center;gap:2px;border:1px solid var(--line-2);border-radius:var(--r-pill);padding:2px}
.qty button{width:24px;height:24px;border-radius:50%;display:grid;place-items:center;
  font-size:1rem;line-height:1;color:var(--ink-70);transition:background .2s,color .2s}
.qty button:hover{background:var(--green);color:#fff}
.qty b{min-width:22px;text-align:center;font-size:.8rem;font-weight:700}
.citem__del{align-self:flex-start;font-size:.72rem;font-weight:700;color:var(--ink-30);transition:color .2s}
.citem__del:hover{color:var(--red)}

.cart__empty{display:none;flex-direction:column;align-items:center;text-align:center;gap:8px;padding:44px 10px}
.cart.is-empty .cart__empty{display:flex}
.cart.is-empty .cart__foot{display:none}
.cart__empty-ic{width:64px;height:64px;border-radius:50%;background:var(--green-soft);color:var(--green);
  display:grid;place-items:center;margin-bottom:4px}
.cart__empty-ic .ic{width:28px;height:28px}
.cart__empty b{font-family:var(--ff-display);font-size:1.02rem}
.cart__empty p{font-size:.85rem;color:var(--ink-50);margin-bottom:8px}

.cart__foot{border-top:1px solid var(--line);padding:18px 22px 20px}
.cart__row{display:flex;align-items:center;justify-content:space-between;gap:10px;font-size:.88rem;margin-bottom:7px}
.cart__row--muted{color:var(--ink-50);font-size:.8rem}
.cart__row--total{padding-top:9px;margin-top:4px;border-top:1px solid var(--line);font-size:1rem}
.cart__row--total b{font-family:var(--ff-display);font-size:1.2rem;color:var(--green)}
/* The two drawer actions swap appearance: checkout reads as a plain text
   line, and Continue shopping is the solid full-width button. */
.cart__checkout{display:block;width:100%;margin-top:12px;text-align:center;
  font-size:.82rem;font-weight:700;color:var(--ink-50);transition:color .2s}
.cart__checkout:hover{color:var(--green)}
.cart__continue{width:100%;margin-top:10px}

/* ---------- FLOATING MOBILE BAR ---------- */
.fabbar{display:none;position:fixed;left:50%;bottom:14px;transform:translateX(-50%);z-index:85;
  width:min(420px,calc(100% - 24px));
  align-items:center;justify-content:space-between;gap:2px;padding:8px 10px;
  /* opaque: this bar is pinned over the page for the entire scroll on phones,
     so a backdrop blur here is a full re-snapshot and re-blur every frame on
     exactly the devices least able to afford one */
  background:#fff;
  border:1px solid var(--line);border-radius:var(--r-pill);
  box-shadow:0 12px 30px -10px rgba(0,0,0,.28)}
/* slides away while the drawer is open so it never sits over the panel */
.fabbar.is-away{transform:translateX(-50%) translateY(140%)}
.fab{position:relative;flex:1;display:flex;flex-direction:column;align-items:center;gap:3px;
  padding:5px 2px;border-radius:var(--r-md);color:var(--ink-50);
  font-size:.63rem;font-weight:700;transition:color .22s,background .22s}
.fab .ic{width:20px;height:20px}
.fab:hover,.fab.is-active{color:var(--green)}
.fab .badge{top:-2px;right:50%;margin-right:-18px}

@media (max-width:1024px){
  .fabbar{display:flex}
  .toast{bottom:88px}
}

/* ---------- FLOATING WHATSAPP ----------
   Bottom right on every page, always visible — it is the quickest way
   to reach a person, and on a food order that is usually what someone
   wants. It owns the corner; back-to-top stacks above it, and both
   move up together on mobile to clear the floating bar.

   Its own green, not the site's: the WhatsApp colour is what makes it
   recognisable at a glance without a label. */
.wafloat{position:fixed;right:20px;bottom:20px;z-index:82;
  width:54px;height:54px;border-radius:50%;
  display:grid;place-items:center;
  background:#25D366;color:#0B2C18;
  box-shadow:0 10px 26px -8px rgba(37,211,102,.85);
  transition:transform .28s cubic-bezier(.34,1.56,.64,1),background .25s}
.wafloat .ic{width:28px;height:28px}
.wafloat:hover{background:#1EBE5A;color:#0B2C18;transform:scale(1.07)}
.wafloat:focus-visible{outline:3px solid var(--ink);outline-offset:3px}

/* The label only exists on a pointer device. On a phone the button is
   obvious and the space is not there to spare. */
.wafloat__txt{position:absolute;right:calc(100% + 12px);white-space:nowrap;
  background:var(--ink);color:#fff;font-size:.78rem;font-weight:700;
  padding:7px 13px;border-radius:var(--r-pill);box-shadow:var(--shadow-md);
  opacity:0;transform:translateX(8px);pointer-events:none;
  transition:opacity .25s,transform .25s}
.wafloat:hover .wafloat__txt,
.wafloat:focus-visible .wafloat__txt{opacity:1;transform:none}
@media (max-width:1024px){ .wafloat__txt{display:none} }

/* A steady pulse for the first few seconds, then it settles. Enough to
   catch the eye once; a permanent animation in the corner of every page
   is an irritation, not an invitation. */
@keyframes wafloat-ping{
  0%   {box-shadow:0 10px 26px -8px rgba(37,211,102,.85), 0 0 0 0 rgba(37,211,102,.55)}
  70%  {box-shadow:0 10px 26px -8px rgba(37,211,102,.85), 0 0 0 16px rgba(37,211,102,0)}
  100% {box-shadow:0 10px 26px -8px rgba(37,211,102,.85), 0 0 0 0 rgba(37,211,102,0)}
}
.wafloat{animation:wafloat-ping 2.4s ease-out 3}
@media (prefers-reduced-motion:reduce){
  .wafloat{animation:none}
  .wafloat:hover{transform:none}
}

/* ---------- FLOATING CART ----------
   Sits directly above the WhatsApp button: 20 + 54 + 12, the same rhythm
   back-to-top used to have before this took the slot.

   The site's own green, deliberately not WhatsApp's: two 54px circles in
   near-identical greens would read as one control split in half. Same size
   and same label behaviour, so they still read as a set. */
.cartfab{position:fixed;right:20px;bottom:86px;z-index:82;
  width:54px;height:54px;border-radius:50%;
  display:grid;place-items:center;
  background:var(--green);color:#fff;box-shadow:0 10px 26px -8px rgba(0,0,0,.45);
  transition:transform .28s cubic-bezier(.34,1.56,.64,1),background .25s}
.cartfab .ic{width:25px;height:25px}
.cartfab:hover{background:var(--ink);transform:scale(1.07)}
.cartfab:focus-visible{outline:3px solid var(--ink);outline-offset:3px}
/* Pushed clear of the circle's edge — the header badge sits inside a square
   button, where 2px in is fine; on a circle that corner is empty space.
   Colour is left to whatever .badge is wearing: theme-lux.css restyles it
   site-wide, and setting a colour here would be silently overridden anyway,
   since `.lux .badge` matches with the same weight and loads later. */
.cartfab .badge{top:-3px;right:-3px;box-shadow:0 0 0 2px #fff}

/* the label, like the WhatsApp one, only exists on a pointer device */
.cartfab__txt{position:absolute;right:calc(100% + 12px);white-space:nowrap;
  background:var(--ink);color:#fff;font-size:.78rem;font-weight:700;
  padding:7px 13px;border-radius:var(--r-pill);box-shadow:var(--shadow-md);
  opacity:0;transform:translateX(8px);pointer-events:none;
  transition:opacity .25s,transform .25s}
.cartfab:hover .cartfab__txt,
.cartfab:focus-visible .cartfab__txt{opacity:1;transform:none}
@media (prefers-reduced-motion:reduce){ .cartfab:hover{transform:none} }

/* back-to-top sits above the cart: 86 + 54 + 12 */
.totop{position:fixed;right:20px;bottom:152px;z-index:80;width:44px;height:44px;border-radius:50%;
  background:var(--green);color:#fff;display:grid;place-items:center;box-shadow:var(--shadow-md);
  opacity:0;transform:translateY(14px);pointer-events:none;transition:opacity .3s,transform .35s,background .25s}
.totop.is-on{opacity:1;transform:none;pointer-events:auto}
.totop:hover{background:var(--ink)}

/* Both corner buttons move up together to clear the floating mobile bar.
   This block has to come AFTER the two rules it overrides: a media query
   carries no extra weight of its own, so with the same selector it is
   source order that decides, and placed earlier it would simply lose. */
@media (max-width:1024px){
  /* the floating cart goes: .fabbar below carries its own Cart button, and
     two of them on one phone screen is one too many. With it gone the corner
     is back to the pair it was, so back-to-top returns to sitting directly
     on top of WhatsApp — 88 + 54 + 12. */
  .cartfab{display:none}
  .wafloat{bottom:88px}
  .totop{bottom:154px}
}

/* Hidden state must clear its own height PLUS the bottom offset, or the pill
   peeks above the viewport edge. opacity/visibility guarantee it either way. */
.toast{position:fixed;left:50%;bottom:24px;z-index:95;background:var(--ink);color:#fff;padding:11px 22px;
  border-radius:var(--r-pill);font-size:.85rem;font-weight:700;box-shadow:var(--shadow-md);
  max-width:calc(100% - 32px);text-align:center;
  opacity:0;visibility:hidden;pointer-events:none;
  transform:translate(-50%,calc(100% + 32px));
  transition:transform .45s cubic-bezier(.34,1.56,.64,1),opacity .3s,visibility .45s}
.toast.is-on{opacity:1;visibility:visible;transform:translate(-50%,0)}

/* split-text helpers */
.w{display:inline-block;overflow:hidden;vertical-align:top;padding-bottom:.12em;margin-bottom:-.12em}
.w__in{display:inline-block;will-change:transform}

/* ---------- 15. RESPONSIVE ---------- */
@media (max-width:1200px){
  .shopgrid{grid-template-columns:repeat(4,1fr)}
  .rail .prod{flex-basis:calc((100% - 3 * var(--gap)) / 4)}
  .rail--videos .vid{flex-basis:calc((100% - 2 * var(--gap)) / 3)}
}
@media (max-width:768px){
  .hbanner__box{aspect-ratio:390/429}
  .hbanner__nav{width:34px;height:34px}
  .hbanner__nav .ic{width:15px;height:15px}
  .hbanner__nav--prev{left:8px}
  .hbanner__nav--next{right:8px}

  /* the category filter becomes one select instead of a wrapped pill row */
  .tabs{display:none}
  .tabsel{display:flex}
  /* the heading and the select stack, so the select gets the full width */
  .shead{flex-direction:column;align-items:stretch;gap:14px}
  .shead--center{align-items:center}
}
/* touch devices have no hover, so the arrows must sit visible by default */
@media (hover:none),(pointer:coarse){
  .hbanner__nav{opacity:1}
}
@media (max-width:1024px){
  /* The sticky nav bar goes altogether on tablet and phone. Its links are
     already hidden at this width, so all it carried was the burger — and
     the floating bar at the bottom has a Menu button that opens the very
     same drawer. The upper row (logo, search, cart, account) stays put. */
  .header{display:none}
  .header__in{min-height:52px}
  .nav{display:none}
  .burger{display:flex;margin-right:auto}
  .catcard{flex-basis:calc((100% - 3 * var(--cgap)) / 4)}
  .highlights__grid{grid-template-columns:repeat(2,1fr)}
  /* brand takes its own row so the four link columns keep a readable width */
  .footer__grid{grid-template-columns:repeat(4,1fr)}
  .footer__brand{grid-column:1/-1}
  .footer__brand p{max-width:52ch}
  /* keep the copyright clear of the floating mobile bar */
  .footer__bar{padding-bottom:84px}
}
@media (max-width:860px){
  .header__upper-in{flex-wrap:wrap;gap:12px}
  .search{order:3;flex-basis:100%;max-width:none}
  .header__util{margin-left:auto}
  .catcard{flex-basis:calc((100% - 2 * var(--cgap)) / 3)}
  .shopgrid{grid-template-columns:repeat(3,1fr)}
  .rail .prod{flex-basis:calc((100% - 2 * var(--gap)) / 3)}
  .rail--videos .vid{flex-basis:calc((100% - var(--gap)) / 2)}
  .ads__grid{grid-template-columns:1fr}
  /* .ctaband__in / __art are gone - the band is one full-width image */
  .posts{grid-template-columns:repeat(2,1fr)}
  .footer__grid{grid-template-columns:repeat(2,1fr);gap:26px 24px}
}
@media (max-width:620px){
  .ticker__group li{padding:8px 18px;font-size:.72rem;gap:7px}
  .ticker .ic{width:14px;height:14px}
  /* the eight tiles become one swipeable row instead of four stacked pairs;
     the negative margin lets it bleed to both screen edges as it scrolls */
  /* one swipeable row on a phone: no wrapping, and the tiles keep a fixed
     width so the next one always peeks in and invites the swipe */
  .catgrid{flex-wrap:nowrap;justify-content:flex-start;
    overflow-x:auto;overscroll-behavior-x:contain;scroll-snap-type:x proximity;
    margin-inline:calc(var(--pad) * -1);padding:6px var(--pad) 10px;
    scrollbar-width:none;-ms-overflow-style:none}
  .catcard{flex:0 0 38%;max-width:none}
  .catgrid::-webkit-scrollbar{display:none}
  .catcard{scroll-snap-align:start}
  .shopgrid{grid-template-columns:repeat(2,1fr)}
  /* Each card keeps its own height here instead of stretching to the rail's.
     A flex row stretches every card to the tallest one anywhere in the rail,
     including the ones scrolled out of sight, and .prod__foot's auto margin
     turned that extra height into a hole between the size pills and the
     price on every other card. Two cards on screen at a time do not need to
     share a height with the ones still off to the right. */
  .rail .prod{flex-basis:calc((100% - var(--gap)) / 2);align-self:flex-start}
  .rail--videos .vid{flex-basis:88%}
  /* the narrow card needs two lines for the name, and the category label
     above it is the first thing that can go to pay for them */
  /* ...and always takes both lines, even for a short name. Otherwise a
     one-line name beside a two-line one puts the size pills on different
     lines in the same row. 2 × the 1.35 line-height, in the heading's own em,
     so it follows the theme's font size. */
  .prod h4{-webkit-line-clamp:2;line-clamp:2;min-height:calc(2em * 1.35)}
  .prod__cat{display:none}
  .posts{grid-template-columns:1fr}
  .highlights__grid{grid-template-columns:1fr}
  .hotline__txt{display:none}
  /* short link lists stay side by side; contact needs the full width for its address */
  .footer__col--contact{grid-column:1/-1}
  .footer__bar-in p{line-height:1.5}
}

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.001ms!important;animation-iteration-count:1!important;transition-duration:.001ms!important}
  /* the blanket rule above would snap the row to its end frame — hold it still
     at the start instead, so the first message set is what stays on screen */
  .ticker__row{transform:none!important}
}
