/* ==========================================================================
   Go Fresh storefront — grocery UI.
   Mobile first. RTL is the SAME stylesheet: anything directional uses logical
   properties (inline-start/end, margin-inline), never left/right.
   ========================================================================== */
:root{
  --dark:#0E4A42;          /* header + hero deep green */
  --dark-2:#0A3A33;
  --lime:#B7E04B;          /* primary call to action */
  --lime-dk:#A5CE3C;
  --lime-ink:#0E3A1C;
  --green:#1F7A3E;
  --ink:#14241C;
  --mut:#6B7B73;
  --line:#E7ECE8;
  --bg:#FFFFFF;            /* the page itself is white */
  --tint:#F6F8F6;          /* the few places that still want a whisper of grey */
  --card:#FFFFFF;
  --warn:#B8860B;
  --danger:#C0392B;
  --r:16px; --r-sm:12px; --r-lg:24px; --pill:999px;
  /* On a white page a drop shadow alone does not define a card, so cards carry a
     hairline border and the shadow is only there to lift them slightly. */
  --sh:none;                /* surfaces sit flat on the page; only overlays lift */
  --sh-lg:0 18px 44px rgba(15,60,45,.14);
  --wrap:1280px;
}
*{box-sizing:border-box}

/* ---------------------------------------------------------------------------
   THE HIDDEN GUARD. Read this before adding another overlay.

   The browser's own rule is [hidden]{display:none} at specificity 0,1,0 — the
   same as any single class. So `.pmodal{display:flex}` written later in this
   file BEATS it, and an element marked hidden stays laid out. That is not a
   cosmetic slip: .pmodal is position:fixed, inset:0, z-index:98, so it sat
   invisibly over every page and swallowed every click on the site.

   This wins outright, and every overlay here is opened by removing the
   attribute, so nothing needs to fight it. !important is the right tool
   exactly once, and this is the once. */
[hidden]{display:none !important}
html{-webkit-text-size-adjust:100%}
/* The system UI font: whatever the device already considers correct — San
   Francisco on Apple, Segoe on Windows, Roboto on Android. Nothing to download,
   nothing to wait for, and every platform's own Arabic falls out of it too. */
body{margin:0;background:var(--bg);color:var(--ink);line-height:1.5;
  font-family:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
  -webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}
body.noscroll{overflow:hidden}
img{max-width:100%;display:block}
a{color:inherit;text-decoration:none}
button{font:inherit;cursor:pointer;border:0;background:none}
/* Type. One scale, three weights. 800 everywhere was shouting: headings are
   700, the things that must be read at a glance (price, quantity) are 600, and
   body text stays 400. Tight tracking only on the large sizes, where it helps. */
h1,h2,h3,h4{margin:0;font-weight:700;letter-spacing:-.022em;line-height:1.2}
h1{font-size:clamp(24px,3.4vw,34px);letter-spacing:-.032em}
h2{font-size:20px}
h3{font-size:17px}
h4{font-size:14px;letter-spacing:-.01em}
b,strong{font-weight:600}
small{font-size:12.5px}

/* icons: one family, sized from the text they sit beside */
.ico{width:1.15em;height:1.15em;flex:0 0 auto;display:inline-block;vertical-align:-.2em}
.ico.xs{width:.85em;height:.85em}
.ico.big{width:42px;height:42px;stroke-width:1.4}
.wrap{max-width:var(--wrap);margin:0 auto;padding-inline:14px}
@media(min-width:800px){.wrap{padding-inline:26px}}
.muted{color:var(--mut)}
.sm{font-size:12.5px}
.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}

/* ---------------------------------------------------------------- buttons */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;
  background:var(--lime);color:var(--lime-ink);padding:12px 22px;border-radius:var(--pill);
  font-weight:600;font-size:14.5px;transition:.16s;white-space:nowrap}
.btn:hover{background:var(--lime-dk)}
.btn.dark{background:var(--dark);color:#fff}
.btn.dark:hover{background:var(--dark-2)}
.btn.soft{background:#EEF3EF;color:var(--ink)}
.btn.soft:hover{background:#E2EBE5}
.btn.outline{background:#fff;color:var(--ink);box-shadow:inset 0 0 0 1.5px var(--line)}
.btn.lg{padding:15px 30px;font-size:16px}
.btn.sm{padding:8px 15px;font-size:13px}
.btn.block{width:100%}
.btn[disabled]{opacity:.5;pointer-events:none}

/* ================================================================= HEADER */
/* The header sticks, and the category bar sticks underneath it. Both need a
   z-index above the grid but below the cart pane. */
/* The header lifts off the page once you scroll, and shrinks as it goes: the
   logo and the controls tighten, the search field loses a little height. Every
   moving part is a transition on ONE class, so the whole thing stays in step. */
.topwrap{background:var(--dark);border-end-start-radius:var(--r-lg);border-end-end-radius:var(--r-lg);
  position:sticky;inset-block-start:0;z-index:50;
  transition:border-radius .22s ease, box-shadow .22s ease, background .22s ease}
/* No drop shadow once it sticks. The bar is a solid dark block against a white
   page — the colour change is already the whole separation, and the shadow only
   put a grey smear under it. */
.topwrap.stuck{box-shadow:0 1px 0 rgba(255,255,255,.06) inset;
  border-end-start-radius:0;border-end-end-radius:0}
.hdr{transition:padding-block .22s ease, gap .22s ease}
.topwrap.stuck .hdr{padding-block:7px}
.logo,.logo .bag,.logo-img,.hic,.hsearch,.hsearch input,.hsearch button,.loc>summary,.wallet-chip{
  transition:height .22s ease, width .22s ease, padding .22s ease, font-size .22s ease, opacity .18s ease}
.topwrap.stuck .logo{font-size:17px}
.topwrap.stuck .logo .bag{width:28px;height:28px}
.topwrap.stuck .logo-img{height:28px}
.topwrap.stuck .hic{width:36px;height:36px}
.topwrap.stuck .hsearch{padding:3px 3px 3px 5px}
.topwrap.stuck .hsearch input{padding-block:7px}
.topwrap.stuck .hsearch button{width:34px;height:34px}
.topwrap.stuck .loc>summary{padding-block:6px}
.topwrap.stuck .promo{opacity:0;max-width:0;overflow:hidden}
@media(prefers-reduced-motion:reduce){
  .topwrap,.hdr,.logo,.logo .bag,.logo-img,.hic,.hsearch,.hsearch input,.hsearch button,
  .loc>summary,.wallet-chip{transition:none}
}
.hdr{display:flex;align-items:center;gap:10px;padding-block:12px;flex-wrap:wrap}
.logo{display:flex;align-items:center;gap:9px;color:#fff;font-weight:700;font-size:19px;letter-spacing:-.03em;flex:0 0 auto}
.logo-img{height:34px;width:auto;max-width:170px;object-fit:contain}
.logo .bag{width:32px;height:32px;border-radius:10px;background:var(--lime);color:var(--lime-ink);
  display:grid;place-items:center}
.logo .bag .ico{width:18px;height:18px}
.logo i{font-style:normal;color:var(--lime)}

/* location picker */
.loc{position:relative;flex:0 0 auto}
.loc>summary{list-style:none;display:flex;align-items:center;gap:7px;cursor:pointer;
  background:rgba(255,255,255,.12);color:#fff;padding:8px 13px;border-radius:var(--pill);
  font-size:13px;font-weight:600;max-width:210px}
.loc>summary::-webkit-details-marker{display:none}
.loc>summary b{font-weight:700;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.loc>summary:hover{background:rgba(255,255,255,.2)}
.loc-pop{position:absolute;inset-block-start:calc(100% + 8px);inset-inline-start:0;z-index:70;
  background:#fff;border-radius:var(--r);box-shadow:var(--sh-lg);padding:8px;min-width:288px}
.loc-pop h4{font-size:11px;text-transform:uppercase;letter-spacing:.1em;color:var(--mut);padding:8px 10px 4px}
.loc-pop a{display:block;padding:10px 12px;border-radius:10px}
.loc-pop a:hover,.loc-pop a.on{background:#F1F6F2}
.loc-pop b{display:block;font-size:14px;font-weight:700}
.loc-pop small{color:var(--mut);font-size:12px}

/* search */
.hsearch{order:9;flex:1 1 100%;display:flex;align-items:center;background:#fff;border-radius:var(--pill);padding:4px 4px 4px 6px}
.hsearch input{flex:1;min-width:0;border:0;outline:none;background:none;padding:10px 12px;font:inherit;font-size:14.5px}
.hsearch button{width:40px;height:40px;border-radius:var(--pill);background:var(--lime);
  color:var(--lime-ink);display:grid;place-items:center;flex:0 0 auto;transition:.15s}
.hsearch button .ico{width:18px;height:18px}
.hsearch button:hover{background:var(--lime-dk)}
.promo{display:none;color:#fff;font-size:13px;font-weight:600;white-space:nowrap}
.promo b{color:var(--lime)}
.hicons{margin-inline-start:auto;display:flex;align-items:center;gap:8px;flex:0 0 auto}
.hic{width:40px;height:40px;border-radius:var(--pill);background:rgba(255,255,255,.12);color:#fff;
  display:grid;place-items:center;position:relative}
.hic .ico{width:19px;height:19px}
.hic:hover{background:rgba(255,255,255,.22)}
.hic.cart{background:#fff;color:var(--dark)}
.hic .n{position:absolute;inset-block-start:-3px;inset-inline-end:-3px;background:var(--lime);color:var(--lime-ink);
  min-width:18px;height:18px;border-radius:var(--pill);font-size:10.5px;font-weight:600;display:grid;place-items:center;padding-inline:4px}
@media(min-width:860px){
  .hsearch{order:0;flex:1 1 auto;max-width:520px;margin-inline:6px}
  .promo{display:block}
}
@media(min-width:1120px){ .hdr{gap:14px} }

/* slide-out menu (details/summary = works with JS off) */

/* ---------------------------------------------- category strip (home) --- */
.cats{display:flex;gap:12px;overflow-x:auto;padding-block:18px 6px;scroll-snap-type:x proximity;scrollbar-width:none}
.cats::-webkit-scrollbar{display:none}
.ccard{flex:0 0 156px;scroll-snap-align:start;position:relative;border-radius:var(--r);overflow:hidden;
  min-height:186px;display:flex;flex-direction:column;justify-content:flex-start;padding:14px 14px 0;
  background:var(--c,#0E7C6B);color:#fff;transition:.18s}
.ccard:hover{transform:translateY(-3px)}
.ccard b{font-size:17px;font-weight:800;letter-spacing:-.02em;line-height:1.15;position:relative;z-index:2}
.ccard span{font-size:11.5px;opacity:.85;position:relative;z-index:2}
.ccard .cimg{margin-block-start:auto;height:96px;width:100%;position:relative;z-index:1}
.ccard .cimg img{width:100%;height:100%;object-fit:cover;object-position:center bottom;
  border-start-start-radius:10px;border-start-end-radius:10px}
.ccard .cemoji{margin-block-start:auto;text-align:center;opacity:.55;padding-block-end:18px}
@media(min-width:760px){.ccard{flex-basis:186px;min-height:212px}}

/* text-only category bar (every page except home) */
.catbar{background:#fff;border-block-end:1px solid var(--line)}
.catbar-in{display:flex;gap:9px;overflow-x:auto;padding-block:10px;scrollbar-width:none}
.catbar-in::-webkit-scrollbar{display:none}
.catbar-in a{padding:8px 14px;border-radius:var(--pill);font-size:13.5px;font-weight:600;
  color:var(--mut);white-space:nowrap}
.catbar-in a:hover{background:#EEF4F0;color:var(--green)}
.catbar-in a.on{background:var(--dark);color:#fff}

/* ------------------------------------------------------------------ hero */
.hero{position:relative;background:var(--dark);border-radius:var(--r-lg);overflow:hidden;
  display:grid;gap:0;margin-block-end:26px}
.hero::before{content:"";position:absolute;inset:0;opacity:.13;
  background-image:radial-gradient(circle at 12% 22%,#fff 1.5px,transparent 1.6px),
                   radial-gradient(circle at 78% 68%,#fff 1.5px,transparent 1.6px);
  background-size:120px 120px}
.hero-txt{position:relative;z-index:2;padding:26px 22px 18px;color:#fff;max-width:560px}
.hero-txt h1{font-size:clamp(26px,5.8vw,46px);line-height:1.06;letter-spacing:-.035em}
.hero-txt p{margin:10px 0 16px;opacity:.86;font-size:14.5px;max-width:430px}
/* Big enough to run off the edges.
 *
 * The hero clips, so the photo is deliberately larger than the box it sits in
 * and loses a little at the top and side. A picture held politely inside its
 * container reads as a stock image dropped in; one that breaks the frame reads
 * as art direction. --ph is written by the parallax below. */
/* PHONE: the photo runs the full width of the hero and is cropped by its
 * bottom edge. Sized by WIDTH, not height — a contained image left a margin of
 * green all round and the hero read as a picture in a box rather than a scene.
 * The hero clips, so the overhang simply disappears into the corner. */
.hero-img{position:relative;z-index:2;display:grid;place-items:end center;
  padding:0;min-block-size:0;overflow:hidden}
.hero-img picture{display:contents}
.hero-img img{block-size:auto;inline-size:112%;max-inline-size:none;
  margin-block-end:-7%;
  translate:0 var(--ph, 0px);
  filter:drop-shadow(0 18px 30px rgba(0,0,0,.30));
  will-change:translate}
@media(min-width:900px){
  .hero{grid-template-columns:1.1fr .9fr;align-items:center}
  .hero-txt{padding:52px 20px 52px 48px}
  [dir=rtl] .hero-txt{padding:52px 48px 52px 20px}
  /* On a wide screen the photo owns its column and then some — it overflows
     the hero's top and outer edge, and the rounded corner crops it. */
  /* DESKTOP: a shallow band, with the photo overflowing it.
   *
   * FLEX with a definite height on the band, and an explicit height on the
   * image — the same shape that fixed the product gallery. No percentage
   * heights (they resolve to nothing against a stretched grid item) and no
   * absolute positioning (which also failed to paint here). The image is an
   * ordinary flex child that is simply taller than its container, and the
   * container clips it. */
  .hero{grid-template-columns:1.02fr .98fr;block-size:clamp(260px, 24vw, 330px)}
  .hero-txt{padding-block:0;align-self:center}
  .hero-img{display:flex;align-items:center;justify-content:flex-end;
    overflow:hidden;padding:0;position:relative}
  /* Bigger, and in proportion. The height is yours from the inspector; the
     width stays auto so the aspect ratio holds — leaving the phone rule's
     `inline-size:112%` in play alongside a fixed height is what stretched it. */
  .hero-img img{flex:0 0 auto;inline-size:auto;max-inline-size:none;
    block-size:clamp(310px, 44vw, 554px);
    margin:0 -12px 0 0;translate:0 var(--ph, 0px)}
  [dir=rtl] .hero-img{justify-content:flex-start}
  [dir=rtl] .hero-img img{margin:0 0 0 -26px}
}

/* ------------------------------------------------------- product grid --- */
.row{margin-block-end:34px}
.row-h{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-block-end:14px}
.row-h h2{font-size:21px}
.row-h a{color:var(--green);font-weight:700;font-size:14px;white-space:nowrap}
.grid{display:grid;grid-template-columns:repeat(2,1fr);gap:12px}
@media(min-width:620px){.grid{grid-template-columns:repeat(3,1fr);gap:16px}}
@media(min-width:980px){.grid{grid-template-columns:repeat(5,1fr);gap:18px}}
.empty{color:var(--mut);text-align:center;padding:46px 0}

.pcard{background:var(--card);border:1px solid var(--line);border-radius:var(--r);
  overflow:hidden;display:flex;flex-direction:column;position:relative;
  transition:box-shadow .18s, transform .18s, border-color .18s}
.pcard:hover{border-color:#C9D8CF}
.pcard.off{opacity:.62}

/* Produce is photographed on white and shown WHOLE — object-fit:contain, never
   cover. Cropping an apple to fill a square is how a grocer loses trust. */
/* Shorter than square, and still object-fit:contain — the product is never
   cropped, it just gets a less tall box, so more of the catalogue fits on a
   screen. */
/* Square, and every one the same height.
   The link inside is positioned ABSOLUTELY. Left in flow it had no height of
   its own, so the image's `height:100%` resolved to auto, the image took its
   intrinsic height, and a square photo made a taller box than a wide one —
   which is why the cards in a row did not line up. An absolute box is
   definite, so the picture always fits inside it and the boxes are identical. */
.pmedia{position:relative;aspect-ratio:1/1;background:#fff;display:block;padding:0;overflow:hidden}
.pmedia>a{position:absolute;inset:12px;display:flex;align-items:center;justify-content:center}
.pmedia img{width:auto;height:auto;max-width:100%;max-height:100%;object-fit:contain;
  transition:transform .3s ease}
.pcard:hover .pmedia img{transform:scale(1.045)}
.pmedia .ph{font-size:46px;opacity:.3;position:absolute;inset-block-start:50%;inset-inline-start:50%;transform:translate(-50%,-50%)}
.pmedia form{position:static;margin:0}

.fav{position:absolute;inset-block-start:10px;inset-inline-end:10px;width:32px;height:32px;
  border-radius:var(--pill);background:#fff;border:1px solid var(--line);color:#9AA8A0;
  display:grid;place-items:center;font-size:14px;z-index:3;transition:.15s}
.fav:hover{color:#E0476B;border-color:#F3C9D3;transform:scale(1.08)}
.fav.on{background:#FFF1F4;border-color:#F6CDD7;color:#E0476B}

/* A fixed three-row body — origin, title, price — so every card in a grid of
   four hundred is exactly the same height and the prices line up across the
   row. The title reserves its two lines whether it needs them or not. */
.pbody{padding:6px 14px 15px;display:grid;grid-template-rows:auto 1fr auto;gap:4px;flex:1;min-height:0}

/* country of origin, with its flag */
.porigin{display:flex;align-items:center;gap:6px;font-size:11.5px;font-weight:500;color:var(--mut);
  min-height:17px;letter-spacing:.01em;overflow:hidden;white-space:nowrap}
.porigin .flag{width:19px;height:13px;object-fit:cover;border-radius:2.5px;
  box-shadow:0 0 0 1px rgba(20,40,30,.12);flex:0 0 auto}

/* One line, always.
   It used to clamp at two and reserve the height for both, so a shelf of
   mostly-one-line names carried a blank line under every card and the handful
   that did wrap pushed their price out of step with the row. The full name is
   on the title attribute and on the product page. */
.pname{font-weight:600;font-size:14.5px;line-height:1.32;letter-spacing:-.008em;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-height:1.32em}
.pcard:hover .pname{color:var(--green)}
.pweight{font-size:12px;color:var(--mut)}

.pprice{display:flex;align-items:baseline;gap:4px;align-self:end;flex-wrap:wrap}
.pprice b{font-size:19px;font-weight:700;letter-spacing:-.03em;font-variant-numeric:tabular-nums}
.pprice i{font-style:normal;font-size:12px;font-weight:600;color:var(--ink)}
.pprice span{font-size:11.5px;color:var(--mut)}
.pprice s{font-size:12px;color:var(--mut);margin-inline-start:3px}

/* ---------------------------------------------- the add control ---------
   The round + and the quantity pill are ONE control in two states. The pill is
   always in the DOM, scaled down against its own trailing edge so it appears to
   grow out of the +; "open" simply lets it out. transform-origin is a logical
   100%/0% pair so the same rule reads correctly in Arabic. */
.padd{position:relative;height:50px;margin-block-start:-34px;margin-inline:14px;
  margin-block-end:8px;z-index:5}
/* The + and the sold-out bell are the same control in the same corner, so they
   share one geometry rule. Two copies drifted apart and the bell ended up
   sitting somewhere else on the card. */
.addfab,.notifyfab{position:absolute;inset-block-start:0;inset-inline-end:0;inset-inline-start:auto;
  inline-size:50px;block-size:50px;border-radius:var(--pill);display:grid;place-items:center;padding:0}
.addfab{background:var(--lime);color:var(--lime-ink);
  transition:transform .22s cubic-bezier(.22,.61,.36,1),opacity .16s}
.addfab .ico{width:22px;height:22px;stroke-width:2.2}
.addfab:hover{transform:scale(1.06)}
.padd.busy .addfab{opacity:.55;pointer-events:none}

.qpill{position:absolute;inset-block-start:0;inset-inline:0;height:50px;border-radius:var(--pill);
  background:#fff;border:1.5px solid var(--line);
  display:flex;align-items:center;justify-content:space-between;padding:0 4px;
  transform:scaleX(.28);transform-origin:100% 50%;opacity:0;pointer-events:none;
  transition:transform .26s cubic-bezier(.22,.61,.36,1),opacity .15s ease}
[dir=rtl] .qpill{transform-origin:0 50%}
.qpill>*{opacity:0;transition:opacity .14s ease .08s}
.padd.open .qpill{transform:none;opacity:1;pointer-events:auto}
.padd.open .qpill>*{opacity:1}
.padd.open .addfab{transform:scale(.4);opacity:0;pointer-events:none}
.qpill button{width:42px;height:42px;border-radius:var(--pill);display:grid;place-items:center;color:var(--ink)}
.qpill button:hover{background:var(--tint)}
.qpill button.qplus{background:var(--lime);color:var(--lime-ink)}
.qpill button.qplus:hover{background:var(--lime-dk)}
.qpill .ico{width:19px;height:19px;stroke-width:2.2}
.qpill .qv{font-size:15px;font-weight:600;min-width:34px;text-align:center;font-variant-numeric:tabular-nums}
@media(prefers-reduced-motion:reduce){.qpill,.addfab,.qpill>*{transition:none}}

.soldout{margin-block-start:auto;padding-block-start:11px;font-size:12.5px;font-weight:600;color:var(--mut)}

/* ------------------------------------------------------------ crumbs etc */
.crumbs{display:flex;gap:7px;flex-wrap:wrap;font-size:13px;color:var(--mut);margin-block:4px 14px}
.crumbs a:hover{color:var(--green)}
.ptitle{font-size:24px;margin-block-end:16px}
.listhead{display:flex;justify-content:space-between;align-items:flex-end;gap:12px;flex-wrap:wrap;margin-block-end:16px}
.listhead h1{font-size:25px}
.sorter select{border:1.5px solid var(--line);background:#fff;border-radius:var(--pill);padding:9px 15px;font:inherit;font-weight:600}
.pager{display:flex;gap:6px;flex-wrap:wrap;margin-block-start:22px}
.pager a{padding:8px 13px;border:1px solid var(--line);border-radius:10px;background:#fff;font-weight:600;font-size:13.5px}
.pager a.on{background:var(--dark);color:#fff;border-color:var(--dark)}

/* ============================================================ PRODUCT PAGE
   30 / 70. One piece of fruit on white does not need half a desktop screen,
   and the words are what actually sell it. */
.pdp{display:grid;gap:24px;margin-block-end:34px}
@media(min-width:900px){
  .pdp{grid-template-columns:50fr 70fr;gap:44px;align-items:start}
  .pdp-media{position:sticky;top:78px}
}
/* FLEX, not grid. With `display:grid; place-items:center` the implicit row is
   auto-sized to the image, so the image's own `max-height:100%` resolves
   against an INDEFINITE grid area and is simply ignored — the picture takes
   its intrinsic height and overflow:hidden slices the bottom off it. That is
   what cropped the apples and then the strawberries. A flex container with a
   definite height resolves the child's percentage max-height properly. */
.gal-main{position:relative;background:#fff;border:1px solid var(--line);border-radius:var(--r-lg);
  overflow:hidden;aspect-ratio:1/1;display:flex;align-items:center;justify-content:center;padding:22px}
.gal-main img{width:auto;height:auto;max-width:100%;max-height:100%;object-fit:contain}
.deliv-badge{position:absolute;inset-block-start:0;inset-inline-start:0;background:var(--dark);color:#fff;
  font-size:11.5px;font-weight:600;padding:8px 15px;border-end-end-radius:var(--r)}

.pdp-info{min-width:0;max-width:68ch}
.pdp-cat{display:flex;align-items:center;gap:8px;flex-wrap:wrap;font-size:13px;color:var(--mut);
  font-weight:500;margin-block-end:7px}
.pdp-cat a:hover{color:var(--green)}
.pdp-cat .dot{opacity:.5}
.pdp-cat .orig{display:inline-flex;align-items:center;gap:6px}
.pdp-cat .flag{width:20px;height:14px;object-fit:cover;border-radius:3px;box-shadow:0 0 0 1px rgba(20,40,30,.12)}
.pdp h1{margin-block-end:9px}
/* The one or two lines that say what this actually is, before any detail. */
.pdp-short{font-size:16px;line-height:1.55;color:#42524A;margin:0 0 16px;max-width:52ch}

/* the claims, as a quiet row rather than a wall of stickers */
.badges{list-style:none;display:flex;flex-wrap:wrap;gap:8px;margin:0 0 18px;padding:0}
.badges li{display:inline-flex;align-items:center;gap:7px;background:var(--tint);border:1px solid var(--line);
  border-radius:var(--pill);padding:7px 14px;font-size:12.5px;font-weight:500;color:#3C4A42}
.badges .ico{width:15px;height:15px;color:var(--green)}

.pdp-price{display:flex;align-items:baseline;gap:6px;margin-block-end:4px;flex-wrap:wrap}
.pdp-price b{font-size:31px;font-weight:700;letter-spacing:-.035em;font-variant-numeric:tabular-nums}
.pdp-price i{font-style:normal;font-size:17px;font-weight:600}
.pdp-price span{color:var(--mut);font-size:14px}
.pdp-price s{color:var(--mut);font-size:16px;margin-inline-start:6px}
.pdp-weightnote{font-size:13px;color:var(--mut);margin:0 0 18px;max-width:50ch;line-height:1.5}
.soldout-big{font-size:15px;font-weight:600;color:var(--mut);margin-block:10px 20px}
.hr{height:1px;background:var(--line);margin-block:22px}

.buybox{display:flex;flex-direction:column;gap:14px;max-width:460px}
.qtyrow{display:flex;align-items:center;gap:12px}
.qtyrow label{font-size:13px;font-weight:500;color:var(--mut)}
.stepper{display:flex;align-items:center;background:#fff;border:1.5px solid var(--line);
  border-radius:var(--pill);overflow:hidden}
.stepper input{width:72px;border:0;text-align:center;font:inherit;font-size:15px;font-weight:600;
  padding:11px 0;outline:none;-moz-appearance:textfield;font-variant-numeric:tabular-nums}
.stepper input::-webkit-outer-spin-button,.stepper input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
.stepper button{width:44px;height:44px;display:grid;place-items:center;color:var(--ink)}
.stepper button:hover{background:var(--tint)}
.stepper .ico{width:17px;height:17px;stroke-width:2.2}
.buyrow{display:grid;grid-template-columns:1fr 1fr;gap:10px}
.ripe{display:flex;gap:9px;flex-wrap:wrap}
.ripe label{display:flex;align-items:center;gap:8px;border:1.5px solid var(--line);background:#fff;
  border-radius:var(--pill);padding:10px 16px;font-size:13.5px;font-weight:500;cursor:pointer}
.ripe input{accent-color:var(--dark)}
.ripe label:has(input:checked){border-color:var(--dark);background:#F1F6F2;font-weight:600}
.linkrow{display:flex;gap:18px;flex-wrap:wrap;margin-block-start:14px}
.linkrow button{display:inline-flex;align-items:center;gap:8px;font-size:13.5px;font-weight:500;color:var(--mut)}
.linkrow button:hover{color:var(--green)}
.pdp-desc{color:#42524A;line-height:1.72;font-size:15px;margin:0 0 20px;max-width:62ch}

.specs{display:grid;grid-template-columns:auto 1fr;gap:9px 26px;font-size:14px;margin-block:0 22px;max-width:440px}
.specs dt{color:var(--mut)}
.specs dd{margin:0;font-weight:500}

.promocards{display:grid;grid-template-columns:1fr;gap:11px}
@media(min-width:620px){.promocards{grid-template-columns:1fr 1fr}}
.promocard{display:flex;gap:12px;align-items:flex-start;background:var(--tint);border-radius:var(--r-sm);padding:14px}
.promocard .ic{color:var(--green);display:grid;place-items:center}
.promocard .ic .ico{width:20px;height:20px}
.promocard b{display:block;font-size:13.5px}
.promocard p{margin:2px 0 0;font-size:12.5px;color:var(--mut);line-height:1.5}

/* phone: the price and the button follow you down the page */
.buybar{position:fixed;inset-inline:0;inset-block-end:0;z-index:60;background:#fff;
  border-block-start:1px solid var(--line);box-shadow:0 -8px 28px rgba(15,60,45,.1);
  padding:10px 14px calc(10px + env(safe-area-inset-bottom))}
.buybar-in{display:flex;align-items:center;justify-content:space-between;gap:14px;
  max-width:var(--wrap);margin:0 auto}
.buybar b{font-size:18px;font-weight:700;font-variant-numeric:tabular-nums}
.buybar span{font-size:12.5px;color:var(--mut);margin-inline-start:5px}
.buybar .btn{padding-inline:28px}
@media(min-width:900px){.buybar{display:none !important}}

/* ------------------------------------------------------------------ cart */
.cartwrap{display:grid;gap:18px}
@media(min-width:900px){.cartwrap{grid-template-columns:1.7fr 1fr;align-items:start}}
.cline{display:grid;grid-template-columns:66px 1fr;gap:12px;background:#fff;border:1px solid var(--line);
  border-radius:var(--r);box-shadow:var(--sh);padding:12px;margin-block-end:10px;align-items:center}
.cline .cm{width:66px;height:66px;border-radius:var(--r-sm);overflow:hidden;background:#fff;
  border:1px solid var(--line);display:grid;place-items:center;padding:5px}
.cline .cm img{width:100%;height:100%;object-fit:contain}
.cq{display:flex;gap:7px;align-items:center;grid-column:1/-1}
.cq input{width:78px;border:1.5px solid var(--line);border-radius:10px;padding:8px;text-align:center;font:inherit;font-weight:700}
.cp{font-weight:800;grid-column:1/-1;text-align:end}
.crm{grid-column:1/-1;text-align:end}
.crm button{color:var(--mut);font-size:12.5px;text-decoration:underline}
@media(min-width:720px){
  .cline{grid-template-columns:72px 1fr auto auto auto;gap:14px}
  .cq,.cp,.crm{grid-column:auto}.cp{min-width:100px}
}
.sum{background:#fff;border:1px solid var(--line);border-radius:var(--r);box-shadow:var(--sh);
  padding:18px;position:sticky;top:14px}
.sum h2{font-size:17px;margin-block-end:12px}
.srow{display:flex;justify-content:space-between;padding-block:7px;font-size:14px}
.srow.tot{border-block-start:1px solid var(--line);margin-block-start:6px;padding-block-start:12px;font-size:18px;font-weight:800}
.estnote{background:#FFF7E6;border:1px solid #F0E0B8;color:#6B5312;border-radius:var(--r-sm);padding:10px 12px;font-size:12.5px;margin-block:10px 14px}
.blank{background:#fff;border:1px solid var(--line);border-radius:var(--r);box-shadow:var(--sh);
  padding:48px 20px;text-align:center}
.blank h1{font-size:21px;margin-block-end:8px}
.blank p{color:var(--mut);margin-block-end:16px}

/* ------------------------------------------------------- flash / footer */
.flash{padding:11px 15px;border-radius:var(--r-sm);margin-block-end:14px;font-size:14px;font-weight:600}
.flash.good{background:#E8F6EE;color:#12713C;border:1px solid #C6E6D3}
.flash.bad{background:#FDECEA;color:var(--danger);border:1px solid #F3CEC8}
.main{padding-block:14px 46px;min-height:50vh}
.promises{display:grid;gap:11px;margin-block-end:32px}
@media(min-width:760px){.promises{grid-template-columns:repeat(3,1fr)}}
.promises div{background:var(--tint);border-radius:var(--r);padding:16px}
.promises b{display:block;margin-block-end:3px;font-size:14.5px}
.promises p{margin:0;color:var(--mut);font-size:13px}
.cms{background:#fff;border:1px solid var(--line);border-radius:var(--r);padding:24px;max-width:820px}
.cms h1{font-size:25px;margin-block-end:14px}
/* A policy page is a document: room to breathe, a readable measure, and
   headings you can scan to find the one clause you came for. */
.cms{line-height:1.75}
.cms h2{font-size:16px;margin:26px 0 8px;color:var(--dark)}
.cms h2:first-of-type{margin-block-start:14px}
.cms p{margin:0 0 12px;max-inline-size:72ch}
.cms ul{margin:0 0 14px;padding-inline-start:20px;max-inline-size:72ch}
.cms li{margin-block-end:5px}
.news{background:var(--dark);color:#fff;border-radius:var(--r-lg);padding:24px;margin-block-end:26px}
.news-in{display:grid;gap:14px}
@media(min-width:800px){.news-in{grid-template-columns:1fr auto;align-items:center}}
.news h3{font-size:19px}
.news p{margin:5px 0 0;opacity:.82;font-size:13.5px}
.nform{display:flex;gap:10px;flex-wrap:nowrap}
.nform input{flex:1;min-width:0;border:0;border-radius:var(--pill);padding:12px 18px;font:inherit}
/* One line at every width. The button never shrinks and never wraps; the
   field takes whatever is left, which is what keeps the two apart instead of
   letting the button ride up against it. */
.nform .btn{flex:0 0 auto;white-space:nowrap}
@media(max-width:560px){
  .nform{gap:8px}
  .nform input{padding-inline:14px;min-inline-size:0}
  .nform .btn{padding-inline:16px}
}
/* The same green as the header, not a second darker one. Two near-identical
   greens top and bottom read as a mistake rather than a gradient. */
.foot{background:var(--dark);color:#DCEBE2}
.foot-in{display:flex;justify-content:space-between;align-items:flex-start;
  gap:28px;flex-wrap:wrap;padding-block:34px 26px}
.foot-id{max-inline-size:38ch}
.foot-reach{display:flex;flex-direction:column;gap:4px;align-items:flex-start}
.foot-reach a{display:inline-flex;align-items:center;gap:8px;opacity:.9}
.foot-reach svg{inline-size:16px;block-size:16px;color:var(--lime)}
@media(min-width:880px){.foot-in{grid-template-columns:1.7fr 1fr 1fr 1fr}}
.foot h4{font-size:13.5px;color:#fff;margin-block-end:9px}
.foot a{display:block;padding-block:4px;opacity:.82;font-size:13.5px}
.foot a:hover{opacity:1}
.foot p{opacity:.8;font-size:13.5px;margin-block:10px}
.foot-b{border-block-start:1px solid rgba(255,255,255,.14);padding-block:15px;font-size:12.5px;
  display:flex;justify-content:space-between;align-items:center;gap:16px;flex-wrap:wrap;opacity:.8}
.foot-b nav{display:flex;gap:18px;flex-wrap:wrap}
.foot-b a{padding:0;opacity:1}
.foot-b a:hover{color:var(--lime)}
.soon{display:grid;place-items:center;min-height:100vh;background:var(--dark);color:#fff;text-align:center;padding:24px}
.soon h1{font-size:30px;margin-block:16px 8px}
.preview-bar{background:var(--warn);color:#fff;text-align:center;font-size:12.5px;font-weight:700;padding:6px}

/* the favourite button sits inside a form; keep the form out of the layout */
.pmedia form{position:static;margin:0}

/* ========================================================== CART PANE =====
   Slides in from the inline-END edge, which is the right in English and the
   LEFT in Arabic — one rule, both languages, because the transform is written
   against a logical property rather than a hard-coded side.

   It is opened by JavaScript on the page you are already on. The previous
   version navigated to ?pane=1 to open, so the transition ran on a freshly
   painted page and was never actually seen. */
.pane-scrim{position:fixed;inset:0;background:rgba(9,32,26,.4);z-index:90;
  opacity:0;transition:opacity .24s ease}
.pane-scrim.on{opacity:1}
.pane{position:fixed;inset-block:0;inset-inline-end:0;z-index:95;width:min(420px,100vw);
  background:#fff;display:flex;flex-direction:column;box-shadow:var(--sh-lg);
  transform:translateX(102%);transition:transform .3s cubic-bezier(.32,.72,0,1);visibility:hidden}
[dir=rtl] .pane{transform:translateX(-102%)}
.pane.on{transform:none;visibility:visible}
@media(prefers-reduced-motion:reduce){.pane,.pane-scrim{transition:none}}

.pane-h{display:flex;align-items:center;justify-content:space-between;gap:10px;
  padding:17px 18px;border-block-end:1px solid var(--line);flex:0 0 auto}
.pane-h h2{font-size:17px;display:flex;align-items:center;gap:9px}
.pane-n{background:var(--dark);color:#fff;font-size:12px;font-weight:600;
  min-width:22px;height:22px;border-radius:var(--pill);display:grid;place-items:center;padding-inline:6px}
.pane-x{width:36px;height:36px;border-radius:var(--pill);background:var(--tint);color:var(--ink);
  display:grid;place-items:center;flex:0 0 auto}
.pane-x:hover{background:#E6EDE8}
.pane-x .ico{width:17px;height:17px}

.pane-body{flex:1;min-block-size:0;overflow-y:auto;overscroll-behavior:contain;
  -webkit-overflow-scrolling:touch;padding:4px 18px}
/* min-block-size:0 is the whole fix. A flex child will not shrink below its
   own content by default, so this box grew to fit every line in the basket and
   overflow-y had nothing left to scroll — the list simply ran off the bottom
   of the pane with the footer pinned over it. */
.pline{display:grid;grid-template-columns:56px 1fr auto;gap:12px;align-items:center;
  padding-block:13px;border-block-end:1px solid var(--line)}
.pline:last-child{border-block-end:0}
.pm{width:56px;height:56px;border:1px solid var(--line);border-radius:var(--r-sm);
  background:#fff;display:grid;place-items:center;overflow:hidden;padding:4px}
.pm img{width:100%;height:100%;object-fit:contain}
.pinfo{display:flex;flex-direction:column;gap:1px;min-width:0}
.pinfo b{font-size:14px;font-weight:500;line-height:1.3}
.pctl{display:flex;flex-direction:column;align-items:flex-end;gap:7px}
.pctl>b{font-size:14px;font-weight:600;white-space:nowrap;font-variant-numeric:tabular-nums}
.pstep{display:flex;align-items:center;border:1.5px solid var(--line);border-radius:var(--pill);overflow:hidden}
.pstep button{width:30px;height:30px;display:grid;place-items:center;color:var(--ink)}
.pstep button:hover{background:var(--tint)}
.pstep .ico{width:14px;height:14px;stroke-width:2.2}
.pstep span{min-width:32px;text-align:center;font-size:13px;font-weight:600;font-variant-numeric:tabular-nums}

.pane-empty{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:10px;text-align:center;padding:30px 22px;color:var(--mut)}
.pane-empty .ico{color:#C6D3CB}
.pane-empty b{font-size:16px;color:var(--ink)}
.pane-empty p{font-size:13.5px;margin:0 0 8px}

.pane-f{flex:0 0 auto;border-block-start:1px solid var(--line);padding:16px 18px;background:#fff}
.pane-full{display:block;text-align:center;margin-block-start:11px;font-size:13.5px;
  font-weight:500;color:var(--mut);text-decoration:underline}

/* ====================================================== search dropdown ==
   Results under the field, each row addable without opening the product. */
.hsearch{position:relative}
.sdrop{position:absolute;inset-block-start:calc(100% + 8px);inset-inline:0;z-index:85;
  background:#fff;border-radius:var(--r);box-shadow:var(--sh-lg);border:1px solid var(--line);
  overflow:hidden;max-height:min(70vh,520px);overflow-y:auto}
.srow-item{display:flex;align-items:center;gap:10px;padding:9px 12px;border-block-end:1px solid var(--line)}
.srow-item:last-of-type{border-block-end:0}
.srow-item:hover{background:var(--tint)}
.sr-main{display:flex;align-items:center;gap:11px;flex:1;min-width:0}
.sr-main img{width:44px;height:44px;object-fit:contain;border:1px solid var(--line);
  border-radius:9px;padding:3px;background:#fff;flex:0 0 auto}
.sr-main span{display:flex;flex-direction:column;min-width:0}
.sr-main b{font-size:14px;font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.sr-main small{color:var(--mut);font-size:12px}
.sr-no{font-size:12px;color:var(--mut);font-weight:500}
.sr-add{position:relative;width:38px;height:38px;flex:0 0 auto}
.sr-fab{position:absolute;inset:0;border-radius:var(--pill);background:var(--lime);color:var(--lime-ink);
  display:grid;place-items:center;font-size:19px;font-weight:600;line-height:1;transition:.16s}
.sr-pill{position:absolute;inset-block:0;inset-inline-end:0;width:104px;border-radius:var(--pill);
  background:#fff;border:1.5px solid var(--line);display:flex;align-items:center;justify-content:space-between;
  transform:scaleX(.36);transform-origin:100% 50%;opacity:0;pointer-events:none;
  transition:transform .24s cubic-bezier(.22,.61,.36,1),opacity .14s}
[dir=rtl] .sr-pill{transform-origin:0 50%}
.sr-add.open .sr-pill{transform:none;opacity:1;pointer-events:auto}
.sr-add.open .sr-fab{opacity:0;transform:scale(.4);pointer-events:none}
.sr-pill button{width:32px;height:32px;border-radius:var(--pill);font-size:15px;color:var(--ink)}
.sr-pill button:hover{background:var(--tint)}
.sr-pill span{font-size:13px;font-weight:600;font-variant-numeric:tabular-nums}
.sr-all{display:block;text-align:center;padding:12px;font-size:13px;font-weight:600;
  color:var(--green);background:var(--tint)}

/* ================================ FORMS, CHECKOUT AND THE ORDER PAGE =====
   Restored: an earlier edit cut from the "filters" heading to "flat cart &
   checkout" to remove a dropdown, and took this whole block with it. These are
   the BASE rules — the compact overrides further down build on them, and the
   sign-in and register pages use .f as well. */

/* --- form fields, shared by checkout and the account pages --- */
.fgrid{display:grid;grid-template-columns:1fr;gap:13px}
/* Contact and address are two grids, and a grid's gap stops at its own edge —
   so the email box sat flush against the Governorate label. Give consecutive
   grids the same 13px, and skip it when the one above is hidden (a signed-in
   shopper sees the contact card instead) so no gap is left behind. */
.fgrid:not([hidden]) + .fgrid{margin-block-start:13px}
@media(min-width:620px){.fgrid{grid-template-columns:1fr 1fr}.f.wide{grid-column:1/-1}}
.f{display:flex;flex-direction:column;gap:5px;min-width:0}
.f>span{font-size:12.5px;font-weight:600;color:var(--mut);display:flex;gap:6px;align-items:baseline}
.f>span i{color:var(--danger);font-style:normal}
.f>span small{font-weight:400;font-size:11.5px}
.f input,.f select,.f textarea{width:100%;font:inherit;font-size:14.5px;color:var(--ink);background:#fff;
  border:1.5px solid var(--line);border-radius:11px;padding:11px 13px;outline:none;transition:border-color .14s}
.f input:focus,.f select:focus,.f textarea:focus{border-color:var(--dark)}
.f textarea{resize:vertical}
.f select:disabled{background:var(--tint);color:var(--mut);cursor:not-allowed}
.phone{display:flex;align-items:center;gap:8px}
.phone b{font-size:14px;font-weight:600;color:var(--mut);flex:0 0 auto}
.phone input{flex:1;min-width:0}
.ferr{color:var(--danger);font-size:12px;font-weight:600;margin:1px 0 0}
.help{color:var(--mut);font-size:12px;margin:3px 0 0}

/* --- the checkout shell --- */
.cowrap{display:grid;gap:20px;margin-block-end:34px}
@media(min-width:960px){.cowrap{grid-template-columns:1.6fr .9fr;align-items:start;gap:30px}}
.cocols{display:flex;flex-direction:column;gap:16px;min-width:0}
.cobox{background:#fff;border:1px solid var(--line);border-radius:var(--r);padding:20px}
.cobox>h2{font-size:17px;display:flex;align-items:center;gap:11px;margin-block-end:15px}
.cobox .num{width:26px;height:26px;border-radius:var(--pill);background:var(--dark);color:#fff;
  font-size:13px;font-weight:600;display:grid;place-items:center;flex:0 0 auto}

/* --- radio choices --- */
.choices{display:grid;gap:9px}
.choice{display:flex;flex-direction:column;gap:3px;cursor:pointer;border:1.5px solid var(--line);
  border-radius:13px;padding:13px 15px;position:relative;transition:.14s}
.choice input{position:absolute;opacity:0;pointer-events:none}
.choice b{font-size:14px;font-weight:600}
.choice small{font-size:12px;color:var(--mut)}
.choice:hover{border-color:#CFE0D6}
.choice:has(input:checked){border-color:var(--dark);background:#F1F6F2}

/* --- the order summary column --- */
.cosum{align-self:start}
.coline{display:grid;grid-template-columns:auto 1fr auto;gap:10px;align-items:baseline;
  padding-block:8px;border-block-end:1px solid var(--line);font-size:13.5px}
/* A rule under the last line separates it from nothing. The band below the
   basket already provides the edge.

   NOT :last-of-type. That means "the last <div> among my siblings", and the
   summary card holds several more divs after the lines — the repeat-order
   offer, the totals — so it matched one of those and the last basket line kept
   its border. "The .coline with no .coline after it" is the thing actually
   meant, and :has is the only way to say it. */
.coline:not(:has(~ .coline)){border-block-end:0}
.coline .q{color:var(--mut);font-weight:600;white-space:nowrap}
.coline .n{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.coline .v{font-weight:600;white-space:nowrap;font-variant-numeric:tabular-nums}
.cosum .srow:first-of-type{margin-block-start:10px}
.estnote.warn{background:#FFF7E6;border-color:#F0E0B8;color:#6B5312}
.backlink{display:block;text-align:center;margin-block-start:12px;font-size:13.5px;
  font-weight:500;color:var(--mut)}

/* --- the order placed page --- */
.done{max-width:860px;margin-inline:auto;padding-block:10px 40px}
.done-top{text-align:center;padding:26px 18px 30px}
.done-top .tick{width:62px;height:62px;border-radius:var(--pill);background:var(--lime);color:var(--lime-ink);
  display:grid;place-items:center;margin:0 auto 16px}
.done-top h1{font-size:clamp(24px,5vw,33px)}
.done-top p{color:var(--mut);margin:9px 0 0}
.orderno{display:inline-flex;align-items:center;gap:9px;background:var(--tint);border-radius:var(--pill);
  padding:9px 18px;margin-block-start:16px;font-size:13.5px;color:var(--mut)}
.orderno b{color:var(--ink);font-size:15px;letter-spacing:.02em}
.donegrid{display:grid;gap:12px;grid-template-columns:1fr;margin-block-end:12px}
@media(min-width:760px){.donegrid{grid-template-columns:repeat(3,1fr)}}
.donecard{background:#fff;border:1px solid var(--line);border-radius:var(--r);padding:17px}
.donecard h3{font-size:12px;text-transform:uppercase;letter-spacing:.08em;color:var(--mut);margin-block-end:9px}
.donecard b{font-size:15px;display:block}
.donecard p{margin:3px 0 0;color:var(--mut);font-size:13.5px;line-height:1.5}
.donecard.wide{margin-block-end:16px}
.donecard.wide h3{margin-block-end:4px}

/* --- the polish pass, also lost in that cut --- */
.row{margin-block-end:40px}
.row-h{margin-block-end:16px}
.row-h h2{font-size:22px;letter-spacing:-.03em}
.row-h a{display:inline-flex;align-items:center;gap:5px;transition:gap .15s}
.row-h a:hover{gap:9px}
.ccard{border:1px solid transparent}
.ccard::after{content:"";position:absolute;inset-block-end:0;inset-inline:0;height:56%;z-index:1;
  background:linear-gradient(to top,rgba(0,0,0,.18),transparent);pointer-events:none}
.hero-txt p{opacity:.8;line-height:1.6}
.promises{gap:14px}
.promises div{background:var(--tint);border:1px solid var(--line);padding:18px}
.promises b{display:flex;align-items:center;gap:8px;font-size:14.5px;margin-block-end:5px}
.promises b .ico{width:17px;height:17px;color:var(--green)}
.btn:active{transform:none}
a:focus-visible,button:focus-visible,select:focus-visible,textarea:focus-visible,
summary:focus-visible{outline:2.5px solid var(--dark);outline-offset:2px;border-radius:6px}
/* …but a round button keeps its shape when focused. The blanket 6px above was
   squaring off the + and the bell. */
.addfab:focus-visible,.notifyfab:focus-visible,.alplus:focus-visible,
.btn:focus-visible{border-radius:var(--pill)}
.f input:focus-visible{outline:2.5px solid var(--dark);outline-offset:1px}
/* The search field sits on the dark bar and is already obviously a search box;
   a ring around it just made the header look broken. */
.hsearch input:focus-visible,.ssheet input:focus-visible{outline:none}
.foot-in{padding-block:40px 30px}
.foot h4{letter-spacing:.02em;font-weight:600;margin-block-end:11px}
.foot a{transition:opacity .14s}
.foot .logo{color:#fff}

/* ================================================= flat cart & checkout ===
   These two pages are long lists of rows. Giving every row its own drop shadow
   turned them into a pile of floating tiles; a hairline is enough to separate
   things that are already in a column. */
.cartwrap .cline,.cartwrap .sum,.cowrap .cobox,.cowrap .sum,.cms,.blank{box-shadow:none}
.cartwrap .cline{border:1px solid var(--line)}
.cartwrap .sum,.cowrap .sum{border:1px solid var(--line)}
.warnline{color:var(--warn);font-weight:600;display:flex;align-items:center;gap:6px}
.estnote{display:flex;gap:8px;align-items:flex-start}
.estnote .ico{flex:0 0 auto;margin-block-start:1px}

/* the phone buy bar must not hide the last row of a page */
@media(max-width:899px){ body:has(.buybar:not([hidden])) .main{padding-block-end:88px} }

/* ------------------------------------------- checkout: mode + repeat ---- */
.choices.two,.choices.four{grid-template-columns:1fr}
@media(min-width:620px){
  .choices.two{grid-template-columns:1fr 1fr}
  .choices.four{grid-template-columns:repeat(2,1fr)}
}
@media(min-width:900px){ .choices.four{grid-template-columns:repeat(4,1fr)} }
.choice b{display:flex;align-items:center;gap:8px}
.choice b .ico{width:17px;height:17px;color:var(--green)}
.choice:has(input:checked) b .ico{color:var(--dark)}
.sublabel{font-size:11.5px;text-transform:uppercase;letter-spacing:.07em;color:var(--mut);
  font-weight:600;margin-block:16px 10px}
.f select:disabled{background:var(--tint);color:var(--mut);cursor:not-allowed}
.repeatcard{background:#F4FAEE;border-color:#DDEDC4}
.repeatcard h3{color:#4A6B18}
.donecard h3{display:flex;align-items:center;gap:8px}
.donecard h3 .ico{width:15px;height:15px}
.done-top .tick{display:grid;place-items:center}
.done-top .tick .ico{width:32px;height:32px;stroke-width:2.4}

/* The count on the collapsed +. No position override here: .addfab is already
   position:absolute, which makes it a containing block for this badge. Setting
   position:relative on it (as an earlier version did) knocked it out of its
   absolute placement and slid the whole button to the left of the card. */
.fabn{position:absolute;inset-block-start:-3px;inset-inline-end:-3px;background:var(--dark);color:#fff;
  min-width:19px;height:19px;border-radius:var(--pill);font-size:10.5px;font-weight:600;
  display:grid;place-items:center;padding-inline:5px;font-variant-numeric:tabular-nums}
.padd.open .fabn{opacity:0}

/* ==================================================== FILTER SIDEBAR =====
   A column beside the grid on desktop; above it, and collapsible, on a phone. */
.listwrap{display:grid;gap:22px;align-items:start}
@media(min-width:900px){.listwrap{grid-template-columns:232px 1fr;gap:30px}}
.listmain{min-width:0}
.fside{display:flex;flex-direction:column;gap:20px;padding:18px;border:1px solid var(--line);
  border-radius:var(--r);background:var(--tint)}
@media(min-width:900px){.fside{position:sticky;top:74px}}
.fside-h{display:flex;align-items:center;justify-content:space-between;gap:10px}
.fside-h h3{font-size:14px;display:flex;align-items:center;gap:8px}
.fside-h h3 .ico{width:16px;height:16px;color:var(--mut)}
.fclear{font-size:12.5px;font-weight:500;color:var(--mut);text-decoration:underline}
.fgroup h4{font-size:11px;text-transform:uppercase;letter-spacing:.07em;color:var(--mut);
  font-weight:600;margin-block-end:10px;display:flex;justify-content:space-between;gap:10px}
.fgroup h4 output{text-transform:none;letter-spacing:0;color:var(--ink);font-variant-numeric:tabular-nums}
.fchips{display:flex;flex-wrap:wrap;gap:7px}
.fchip{display:inline-flex;align-items:center;gap:7px;background:#fff;border:1.5px solid var(--line);
  border-radius:var(--pill);padding:7px 13px;font-size:12.5px;font-weight:500;cursor:pointer;transition:.14s}
.fchip input{position:absolute;opacity:0;pointer-events:none}
.fchip .ico{width:14px;height:14px;color:var(--mut)}
.fchip:hover{border-color:#CFE0D6}
.fchip:has(input:checked){border-color:var(--dark);background:var(--dark);color:#fff}
.fchip:has(input:checked) .ico{color:var(--lime)}
.fgroup select{width:100%;border:1.5px solid var(--line);border-radius:10px;padding:9px 11px;
  font:inherit;font-size:13px;background:#fff}
.fgroup input[type=range]{width:100%;accent-color:var(--dark)}

/* ------------------------------------------------ checkout: layout bits ---
   The compaction pass was reverted at Hassan's request — the base rules above
   are the sizing now. What stays here is only what the compact pass ADDED:
   the one-row day and time picker, and the branch card. */
.whenrow{display:grid;gap:13px}
@media(min-width:520px){.whenrow{grid-template-columns:1fr 1fr}}
.whenrow select{font-variant-numeric:tabular-nums}

.pickfrom{display:flex;align-items:center;gap:12px;background:var(--tint);border:1px solid var(--line);
  border-radius:12px;padding:13px 15px;margin-block-start:12px}
.pickfrom .ico{width:20px;height:20px;color:var(--green);flex:0 0 auto}
.pickfrom div{flex:1;min-width:0;display:flex;flex-direction:column}
.pickfrom b{font-size:14px}
.pickfrom span{font-size:12.5px;color:var(--mut)}
.pickchange{font-size:13px;font-weight:500;color:var(--green);text-decoration:underline;flex:0 0 auto}

.choices.two,.choices.four{grid-template-columns:1fr}
@media(min-width:620px){
  .choices.two{grid-template-columns:1fr 1fr}
  .choices.four{grid-template-columns:repeat(2,1fr)}
}
@media(min-width:900px){ .choices.four{grid-template-columns:repeat(4,1fr)} }
.choice b{display:flex;align-items:center;gap:8px}
.choice b .ico{width:17px;height:17px;color:var(--green)}
.choice:has(input:checked) b .ico{color:var(--dark)}
.sublabel{font-size:11.5px;text-transform:uppercase;letter-spacing:.07em;color:var(--mut);
  font-weight:600;margin-block:16px 10px}
.repeatcard{background:#F4FAEE;border-color:#DDEDC4}
.repeatcard h3{color:#4A6B18}
.donecard h3{display:flex;align-items:center;gap:8px}
.donecard h3 .ico{width:15px;height:15px}
.done-top .tick .ico{width:32px;height:32px;stroke-width:2.4}

/* ------------------------------------------ repeat, inside the summary --- */
.repeatbox{position:relative;border:1px solid var(--line);border-radius:12px;padding:12px;margin-block:12px 4px}
.repeatbox>label{display:flex;align-items:flex-start;gap:10px;cursor:pointer}
.repeatbox>label input{accent-color:var(--dark);margin-block-start:3px;flex:0 0 auto}
.repeatbox>label span{display:flex;flex-direction:column;font-size:13.5px;font-weight:500}
.repeatbox>label small{font-size:11.5px;color:var(--mut);font-weight:400;line-height:1.45}
.repeatbox>label small+small{margin-block-start:4px}
/* The eligibility line is a statement about THIS basket, so it carries the
   brand colour; the reason underneath stays quiet. */
.rb-ok{color:var(--dark);font-weight:600}
.repeatopts{display:grid;gap:7px;margin-block-start:11px;padding-block-start:11px;
  border-block-start:1px solid var(--line)}
.freq{display:flex;align-items:center;gap:9px;cursor:pointer;border:1.5px solid var(--line);
  border-radius:10px;padding:9px 12px;font-size:13px;font-weight:500;position:relative;transition:.14s}
.freq input{position:absolute;opacity:0;pointer-events:none}
.freq .ico{width:15px;height:15px;color:var(--mut)}
.freq:hover{border-color:#CFE0D6}
.freq:has(input:checked){border-color:var(--dark);background:#F1F6F2}
.freq:has(input:checked) .ico{color:var(--dark)}

/* ======================================================= WALLET CHIP =====*/
/* Shown at every width. It was desktop-only, which is backwards: the balance
   is most worth knowing on the device people actually shop on, and a customer
   with credit sitting unspent is the whole reason to surface it. */
.wallet-chip{display:inline-flex;align-items:center;gap:9px;background:rgba(255,255,255,.14);
  color:#fff;border-radius:var(--pill);padding:6px 14px 6px 11px;line-height:1.15;
  flex:0 1 auto;min-inline-size:0}
.wallet-chip:hover{background:rgba(255,255,255,.24)}
.wallet-chip .ico{width:18px;height:18px;color:var(--lime);flex:0 0 auto}
.wallet-chip span{display:flex;flex-direction:column;min-inline-size:0}
.wallet-chip b{font-size:13px;font-weight:600;font-variant-numeric:tabular-nums;
  white-space:nowrap}
.wallet-chip small{font-size:10.5px;opacity:.75;white-space:nowrap}

/* ============================================== SIGN IN / REGISTER ======= */
.authwrap{display:grid;gap:26px;margin-block:8px 44px}
@media(min-width:880px){.authwrap{grid-template-columns:1fr 330px;gap:48px;align-items:start}}
.authcard{border:1px solid var(--line);border-radius:var(--r-lg);padding:30px;max-width:460px}
.authcard h1{font-size:26px;margin-block-end:7px}
.authsub{color:var(--mut);font-size:14px;margin:0 0 22px}
.authform{display:flex;flex-direction:column;gap:14px}
.authform .btn{margin-block-start:6px}
.authalt{font-size:13.5px;color:var(--mut);margin-block:16px 0;text-align:center}
.authalt a{color:var(--green);font-weight:600;text-decoration:underline}
.authside{padding-block-start:6px}
.authside h3{font-size:15px;margin-block-end:14px}
.authside ul{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:18px}
.authside li{display:flex;gap:12px}
.authside li .ico{width:20px;height:20px;color:var(--green);flex:0 0 auto;margin-block-start:2px}
.authside b{font-size:14px;display:block;margin-block-end:2px}
.authside p{margin:0;font-size:13px;color:var(--mut);line-height:1.55}

/* ============================================================= ACCOUNT === */
.acct-head{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;
  flex-wrap:wrap;margin-block:6px 22px}
.acct{display:grid;gap:26px;margin-block-end:40px}
@media(min-width:900px){.acct{grid-template-columns:1.5fr 1fr;gap:38px;align-items:start}}
.acct-h{font-size:15px;margin-block:0 14px}

.wallet{display:grid;gap:14px;margin-block-end:30px}
@media(min-width:560px){.wallet{grid-template-columns:1fr 1fr}}
.w-money,.w-points{border-radius:var(--r);padding:20px;display:flex;flex-direction:column;gap:3px}
.w-money{background:var(--dark);color:#fff}
.w-points{background:var(--tint);border:1px solid var(--line)}
.w-money span,.w-points span{font-size:11.5px;text-transform:uppercase;letter-spacing:.07em;opacity:.7}
.w-money b,.w-points b{font-size:30px;font-weight:700;letter-spacing:-.03em;font-variant-numeric:tabular-nums}
.w-money small{font-size:12px;opacity:.72;line-height:1.5}
.w-points small{font-size:12px;color:var(--mut)}
.w-points .btn{align-self:flex-start;margin-block-start:9px}

.ordrow{display:grid;grid-template-columns:auto 1fr auto auto;gap:12px;align-items:center;
  padding:13px 0;border-block-end:1px solid var(--line);font-size:13.5px}
.ordrow:hover .o-no{color:var(--green)}
.o-no{font-weight:600}
.o-when,.o-status{color:var(--mut);font-size:12.5px}
.o-total{font-weight:600;font-variant-numeric:tabular-nums}

.wrow{display:flex;align-items:flex-start;justify-content:space-between;gap:14px;
  padding-block:11px;border-block-end:1px solid var(--line)}
.wrow div:first-child{display:flex;flex-direction:column;gap:1px;min-width:0}
.wrow b{font-size:13.5px}
.wamt{text-align:end;display:flex;flex-direction:column;gap:2px;white-space:nowrap;
  font-size:13px;font-weight:600;font-variant-numeric:tabular-nums}
.wamt .up{color:#15803D}
.wamt .down{color:var(--mut)}

/* Wallet credit on the checkout summary.
   It is a line in the breakdown, so it is styled by .srow like Subtotal and
   Delivery and nothing else. It used to be a tinted, bordered box because it
   carried a checkbox; the checkbox moved to the payment methods and the box
   stayed behind, making one row of the bill look like a different kind of
   thing from the rows above it. */
.srow b.down{color:#15803D}

.catbar-in a.empty{opacity:.45}
.catbar-in a.empty:hover{opacity:.7}

/* ======================================== THE BAR ABOVE THE BRAND BAR =====
   Branch on one side, language on the other. Both are things you want to see
   before you start, and neither deserves a slot in the brand bar itself. */
/* Lime, so the two bars read as one brand block rather than a grey afterthought. */
.tinybar{background:var(--lime);color:var(--lime-ink);font-size:12.5px}
/* Nothing in this bar may push the page wider than the screen.
   It is a space-between row with a sentence on one side and the language
   switch on the other; without min-inline-size:0 the sentence refuses to
   shrink, the row grows past the viewport, and the WHOLE PAGE gains a
   horizontal scroll — which is what made every page look shifted left on a
   phone. The branch name ellipsises instead; the language switch never does. */
.tinybar-in{display:flex;align-items:center;justify-content:space-between;gap:12px;
  min-height:34px;padding-block:5px;min-inline-size:0}
.tb-branch{display:inline-flex;align-items:center;gap:7px;color:var(--lime-ink);font:inherit;
  font-size:12.5px;padding:0;text-align:start;min-inline-size:0;flex:0 1 auto;overflow:hidden}
.tb-branch > span{min-inline-size:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tb-branch .ico{width:14px;height:14px;color:var(--dark);flex:0 0 auto;opacity:.75}
.tb-branch b{color:var(--lime-ink);font-weight:700;margin-inline-start:4px}
.tb-branch i{font-style:normal;text-decoration:underline;margin-inline-start:7px;opacity:.72}
.tb-branch:hover i{opacity:1}
.tb-lang{display:flex;align-items:center;gap:6px;color:rgba(14,58,28,.4);font-size:12px;flex:0 0 auto}
.tb-lang a{font-weight:600;color:rgba(14,58,28,.66);padding:2px 4px}
.tb-lang a.on{color:var(--lime-ink);text-decoration:underline}

/* =============================== STICKY HEADER + CATEGORY BAR ============ */
/* A first-paint guess only — shop.js measures the real header and overwrites
   both of these, because a wrong value here shows a strip of the page between
   the two sticky bars. */
:root{--hdr-h:62px;--sub-h:0px}
@media(min-width:860px){:root{--hdr-h:70px}}
.catbar{inset-block-start:var(--hdr-h)}
.catbar-in{scroll-behavior:smooth}
.catsec{scroll-margin-block-start:calc(var(--hdr-h) + 62px);margin-block-end:38px}
.catsec .row-h h2{display:flex;align-items:center;gap:10px}
.catcount{background:var(--tint);color:var(--mut);font-size:12px;font-weight:600;
  min-width:22px;height:22px;border-radius:var(--pill);display:grid;place-items:center;padding-inline:7px}
.listhead{scroll-margin-block-start:calc(var(--hdr-h) + 62px)}
.hic.sbtn{display:none}

/* The origin row in the product spec list: same flag treatment as the card. */
dd.origin{display:flex;align-items:center;gap:6px}
dd.origin .flag{width:19px;height:13px;object-fit:cover;border-radius:2.5px;
  box-shadow:0 0 0 1px rgb(0 0 0 / .08)}

/* Wide pages: the grid should use the window, not a 1280px column. */
.main.wide{max-width:none}
.wrap.main.wide{padding-inline:16px}
@media(min-width:1100px){.wrap.main.wide{padding-inline:32px}}
@media(min-width:1400px){.main.wide .grid{grid-template-columns:repeat(6,1fr)}}
@media(min-width:1750px){.main.wide .grid{grid-template-columns:repeat(7,1fr)}}
@media(min-width:2100px){.main.wide .grid{grid-template-columns:repeat(8,1fr)}}

/* ---- the phone header: icons only, search behind a magnifier ------------ */
@media(max-width:859px){
  .hdr{gap:8px;padding-block:10px;flex-wrap:nowrap}
  .topwrap{border-end-start-radius:16px;border-end-end-radius:16px}
  .logo{font-size:17px}
  .logo .bag{width:28px;height:28px}
  .logo-img{height:28px;max-width:110px}
  .loc{display:none}          /* the branch lives in the strip above */
  .promo{display:none}
  .hsearch{display:none}      /* replaced by the magnifier + sheet */
  .hic.sbtn{display:grid}
  .hicons{gap:6px;margin-inline-start:auto;min-inline-size:0}
  .hic{width:36px;height:36px}
  .hic .ico{width:17px;height:17px}

  /* On a phone the chip shows the MONEY only. Four circular buttons and a
     logo already own the bar, and one line keeps the chip exactly as tall as
     the buttons beside it. The points are on the account page, one tap away.
     The logo is allowed to shrink so the chip never pushes the cart off. */
  .logo{min-inline-size:0;flex:0 1 auto;overflow:hidden}
  .wallet-chip{height:36px;gap:6px;padding-inline:10px 12px;order:-1}
  .wallet-chip .ico{width:15px;height:15px}
  .wallet-chip small{display:none}
  .wallet-chip b{font-size:12.5px}
  .catbar-in a{padding:10px 12px;font-size:13px}
  .tinybar-in{min-height:32px;font-size:12px}
  .tb-branch span{display:inline}
}

/* ================================================= THE SEARCH SHEET ======*/
.ssheet{position:fixed;inset:0;z-index:97;background:rgba(9,32,26,.45);
  opacity:0;transition:opacity .2s}
.ssheet.on{opacity:1}
.ssheet-in{position:absolute;inset-block-start:0;inset-inline:0;background:#fff;
  padding:12px;max-height:100vh;display:flex;flex-direction:column;
  transform:translateY(-12px);transition:transform .2s}
.ssheet.on .ssheet-in{transform:none}
.ssheet-bar{display:flex;align-items:center;gap:10px}
.ssheet-bar input{flex:1;min-width:0;border:1.5px solid var(--line);border-radius:var(--pill);
  padding:11px 16px;font:inherit;font-size:15px;outline:none}
.ssheet-x{font:inherit;font-size:14px;font-weight:500;color:var(--mut);padding:6px}
.sdrop-sheet{position:static;margin-block-start:10px;box-shadow:none;border:0;
  max-height:calc(100vh - 90px);border-radius:0}
.sdrop-sheet:empty{display:none}

/* the dropdown, given more room */
.sdrop{max-height:min(74vh,620px)}
.srow-item{padding:11px 13px}
.sr-main img{width:52px;height:52px}
.sr-main b{font-size:14.5px}
.sr-add{width:40px;height:40px}
.sr-pill{width:112px}

/* ============================================ THE PRODUCT OVERLAY ========
   A bottom sheet on a phone, a centred dialog on a desktop. Same element. */
.pmodal{position:fixed;inset:0;z-index:98;display:flex;align-items:flex-end;justify-content:center}
.pmodal-scrim{position:absolute;inset:0;background:rgba(9,32,26,.5);opacity:0;transition:opacity .26s}
.pmodal.on .pmodal-scrim{opacity:1}
.pmodal-card{position:relative;background:#fff;width:100%;max-height:92vh;overflow-y:auto;
  border-start-start-radius:22px;border-start-end-radius:22px;padding:8px 18px 26px;
  transform:translateY(100%);transition:transform .3s cubic-bezier(.32,.72,0,1)}
.pmodal.on .pmodal-card{transform:none}
/* The grip and the close button ride along with the scroll.
 *
 * They were absolutely positioned inside the card — and the card is what
 * scrolls, so a few swipes down the description and the only way out of the
 * sheet had scrolled off the top. Sticky keeps them where a thumb expects
 * them however far down the page you are. */
.pmodal-grip{position:sticky;inset-block-start:0;z-index:4;
  inline-size:44px;block-size:4px;border-radius:99px;background:#D9E2DC;
  margin:6px auto 12px;cursor:grab}
.pmodal-x{position:sticky;inset-block-start:6px;z-index:5;
  margin-inline-start:auto;margin-block-start:-30px;margin-block-end:4px;
  inline-size:34px;block-size:34px;
  border-radius:var(--pill);background:var(--tint);color:var(--ink);display:grid;place-items:center}
.pmodal-x .ico{width:16px;height:16px}
.pmodal-load{display:grid;place-items:center;min-height:240px}
.pmodal-load span{width:26px;height:26px;border:2.5px solid var(--line);border-top-color:var(--dark);
  border-radius:50%;animation:spin .7s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
.modal-full{display:inline-block;margin-block-start:16px;font-size:13.5px;font-weight:500;
  color:var(--green);text-decoration:underline}
.pdp.in-modal{gap:20px}
.pdp.in-modal .pdp-media{position:static}
@media(min-width:760px){
  .pmodal{align-items:center;padding:24px}
  .pmodal-card{max-width:900px;border-radius:var(--r-lg);padding:26px 30px 30px;max-height:88vh;
    transform:translateY(16px) scale(.98)}
  .pmodal.on .pmodal-card{transform:none}
  .pmodal-grip{display:none}
  .pdp.in-modal{grid-template-columns:44fr 56fr;gap:32px}
}
@media(prefers-reduced-motion:reduce){.pmodal-card,.pmodal-scrim,.ssheet,.ssheet-in{transition:none}}

/* ============================================ FILTERS AS A SLIDE PANE ====*/
.fbtn{display:inline-flex;align-items:center;gap:8px;border:1.5px solid var(--line);
  border-radius:var(--pill);padding:9px 17px;font:inherit;font-size:13.5px;font-weight:500;
  background:#fff;margin-block-end:14px}
.fbtn .ico{width:16px;height:16px;color:var(--mut)}
.fbtn:hover{border-color:#CFE0D6;background:var(--tint)}
.fcount{background:var(--lime);color:var(--lime-ink);min-width:19px;height:19px;border-radius:var(--pill);
  font-size:11px;font-weight:600;display:grid;place-items:center;padding-inline:5px}
.fscrim{position:fixed;inset:0;background:rgba(9,32,26,.42);z-index:88;opacity:0;transition:opacity .22s}
.fscrim.on{opacity:1}
.fside-x{display:grid;place-items:center;width:32px;height:32px;border-radius:var(--pill);
  background:#fff;color:var(--ink)}
.fside-x .ico{width:16px;height:16px}

/* phone and tablet: a pane that slides in from the inline-start edge */
@media(max-width:899px){
  .fside{position:fixed;inset-block:0;inset-inline-start:0;z-index:92;width:min(320px,86vw);
    border-radius:0;border:0;border-inline-end:1px solid var(--line);background:#fff;
    padding:18px;overflow-y:auto;transform:translateX(-102%);
    transition:transform .28s cubic-bezier(.32,.72,0,1)}
  [dir=rtl] .fside{transform:translateX(102%)}
  .fside.on{transform:none}
}
/* desktop: the button is unnecessary, the pane is simply the column */
@media(min-width:900px){
  .fbtn,.fscrim,.fside-x{display:none !important}
  .fside{position:sticky;inset-block-start:calc(var(--hdr-h) + 64px)}
}

/* ==================================================== SOLD OUT + NOTIFY ==
   A sold-out card shows no price and no +. The bell is the only offer left. */
/* Laid out rather than positioned.
 *
 * The bell shares .addfab's absolute rule, and on some cards it still landed
 * short of the corner — a containing-block difference I could not pin down from
 * the rendered page. A one-item flex row that pushes its child to the end
 * cannot land anywhere else, so the guesswork stops here. */
/* Exactly the mechanism the + button uses, and nothing else.
 *
 * This looked for a long time like a CSS problem and was not one. The markup
 * for a lit and an unlit bell is byte-identical, and the bell shares .addfab's
 * geometry — but on clicking notify the script added the class `done` to the
 * form, and `.done` is the ORDER CONFIRMATION page's wrapper: max-width 860px,
 * margin-inline auto, padding-block 10px 40px. That wiped .padd's side margins
 * and doubled its height, so the bell jumped out of the corner and into the
 * middle of the card. The class is `notified` now; nothing here needed to
 * change. */
.padd.notify{display:block}
.notifyfab{background:#fff;border:1.5px solid var(--line);color:var(--mut);transition:.16s}
.notifyfab .ico{width:21px;height:21px}
.notifyfab:hover{border-color:var(--dark);color:var(--dark);transform:scale(1.05)}
.notifyfab.on{background:var(--dark);border-color:var(--dark);color:#fff}
.padd.notify.notified .notifyfab{pointer-events:none}
.pcard.off{opacity:1}                       /* the words say sold out; no need to dim it */
.pcard.off .pmedia img{filter:grayscale(.55);opacity:.72}
.soldout{align-self:end;font-size:14px;font-weight:600;color:var(--mut);padding-block-start:0}

.soldbox{border:1px solid var(--line);border-radius:var(--r);padding:18px;max-width:420px}
.soldout-big{font-size:16px;font-weight:600;color:var(--mut);margin:0 0 12px}
.soldbox .btn{width:100%}
.soldbox .btn.on{background:var(--dark);color:#fff}
.soldbox p.muted{margin:10px 0 0;text-align:center}

/* the guest dialog */
.nmodal{position:fixed;inset:0;z-index:99;display:flex;align-items:center;justify-content:center;padding:18px}
.nmodal-scrim{position:absolute;inset:0;background:rgba(9,32,26,.5);opacity:0;transition:opacity .24s}
.nmodal.on .nmodal-scrim{opacity:1}
.nmodal-card{position:relative;background:#fff;border-radius:var(--r-lg);padding:26px;
  width:min(420px,100%);max-height:90vh;overflow-y:auto;display:flex;flex-direction:column;gap:13px;
  transform:translateY(14px) scale(.98);opacity:0;transition:transform .26s cubic-bezier(.32,.72,0,1),opacity .2s}
.nmodal.on .nmodal-card{transform:none;opacity:1}
.nmodal-card h2{font-size:18px;display:flex;align-items:center;gap:10px}
.nmodal-card h2 .ico{width:19px;height:19px;color:var(--green)}
.nsub{color:var(--mut);font-size:13px;margin:-6px 0 4px;line-height:1.55}
.nerr{color:var(--danger);font-size:13px;font-weight:600;margin:0}
@media(prefers-reduced-motion:reduce){.nmodal-card,.nmodal-scrim{transition:none}}

/* a confirmation that fades on its own */
/* Above the fixed buy bar, not across it — the bar is the thing you are
   looking at when the toast fires. */
.toast{position:fixed;inset-block-end:22px;inset-inline:0;margin-inline:auto;z-index:120;
  width:max-content;max-width:calc(100vw - 32px);background:var(--dark);color:#fff;
  padding:13px 22px;border-radius:var(--pill);font-size:14px;font-weight:500;
  box-shadow:var(--sh-lg);opacity:0;transform:translateY(12px);transition:.28s}
.toast.on{opacity:1;transform:none}

/* the draft badge sits above the toast's corner, not under it */
.preview-dot{position:fixed;inset-block-end:16px;inset-inline-end:16px;z-index:110;
  display:inline-flex;align-items:center;gap:7px;background:var(--warn);color:#fff;
  padding:8px 14px;border-radius:var(--pill);font-size:12px;font-weight:600;box-shadow:var(--sh-lg)}
.preview-dot .ico{width:14px;height:14px}

/* ============================== THE TWO-ROW CATEGORY BAR ================
   Row one is aisles and navigates; row two is the shelves inside the aisle
   you are on and scrolls. Both sticky, one under the other. */
/* Sticky, under the header. This rule carries the position because an earlier
   edit dropped it from the base .catbar rule and the offset alone did nothing —
   `inset-block-start` on a static element is inert. */
.catbar{padding:0;position:sticky;z-index:45;inset-block-start:var(--hdr-h);
  transition:box-shadow .22s ease}
.catbar.stuck{box-shadow:0 4px 12px rgba(15,60,45,.07)}
.catbar-in{display:flex;gap:9px;overflow-x:auto;padding-block:9px;scrollbar-width:none}
.catbar-in::-webkit-scrollbar{display:none}
.catbar-in a{padding:8px 16px;border-radius:var(--pill);font-size:14px;font-weight:500;
  color:var(--mut);white-space:nowrap;flex:0 0 auto;transition:.15s}
.catbar-in a::after{display:none}
.catbar-in a:hover{background:var(--tint);color:var(--ink)}
.catbar-in a.on{background:var(--lime);color:var(--lime-ink);font-weight:600}

.subbar{border-block-start:1px solid var(--line);background:#FAFCFA;overflow:hidden}
.subbar-in{display:none;gap:4px;overflow-x:auto;padding-block:7px;scrollbar-width:none}
.subbar-in::-webkit-scrollbar{display:none}
.subbar-in.on{display:flex}
.subbar-in a{display:inline-flex;align-items:center;gap:6px;padding:6px 13px;border-radius:var(--pill);
  font-size:13px;font-weight:500;color:var(--mut);white-space:nowrap;flex:0 0 auto}

.subbar-in a:hover{background:#EEF4F0;color:var(--ink)}
.subbar-in a.on{background:#E4EFE6;color:var(--dark);font-weight:600}

.subbar-in a.empty{opacity:.45}
/* the sub row only exists on wide-ish screens as a second line; on a phone it
   simply scrolls like the first */
:root{--sub-h:0px}

.catsec{scroll-margin-block-start:calc(var(--hdr-h) + 56px + var(--sub-h))}
.listhead{scroll-margin-block-start:calc(var(--hdr-h) + 56px + var(--sub-h))}
/* Desktop only. On a phone .fside is a full-height drawer pinned with
   inset-block:0, and a top offset here pushed it halfway down the screen. */
@media(min-width:900px){
  .fside{top:calc(var(--hdr-h) + 60px + var(--sub-h)) !important}
}
.catsec.sub .row-h h2{font-size:19px}

/* =========================================== the aisle-switch spinner ===
   Switching aisle is a page load. A spinner over the page says so plainly —
   a hairline at the very top is easy to miss on a phone. */
.pageload{position:fixed;inset:0;z-index:130;display:grid;place-items:center;
  background:rgba(255,255,255,.62);backdrop-filter:blur(1.5px);
  opacity:0;transition:opacity .16s}
.pageload.on{opacity:1}
.pageload span{width:38px;height:38px;border:3px solid rgba(14,74,66,.16);
  border-top-color:var(--dark);border-radius:50%;animation:spin .7s linear infinite}
@media(prefers-reduced-motion:reduce){.pageload span{animation-duration:1.6s}}

/* ================================================== the branch picker ===*/
.bmodal{position:fixed;inset:0;z-index:99;display:flex;align-items:center;justify-content:center;padding:18px}
.bmodal-card{position:relative;background:#fff;border-radius:var(--r-lg);padding:26px;
  box-shadow:0 24px 60px rgba(10,40,25,.22),0 4px 14px rgba(10,40,25,.10);
  width:min(420px,100%);display:flex;flex-direction:column;gap:12px;
  transform:translateY(14px) scale(.98);opacity:0;
  transition:transform .26s cubic-bezier(.32,.72,0,1),opacity .2s}
.bmodal.on .bmodal-card{transform:none;opacity:1}
.bmodal-card h2{font-size:18px;display:flex;align-items:center;gap:10px}
.bmodal-card h2 .ico{width:19px;height:19px;color:var(--green)}
.blist{display:flex;flex-direction:column;gap:9px;margin-block-start:4px}
.bopt{display:flex;align-items:center;justify-content:space-between;gap:12px;
  border:1.5px solid var(--line);border-radius:13px;padding:14px 16px;transition:.14s}
.bopt span{display:flex;flex-direction:column;gap:2px}
.bopt b{font-size:15px}
.bopt small{display:flex;align-items:center;gap:6px;font-size:12.5px;color:var(--mut)}
.bopt small .ico{width:13px;height:13px}
.bopt:hover{border-color:#CFE0D6;background:var(--tint)}
.bopt.on{border-color:var(--dark);background:#F1F6F2}
.bopt>.ico{width:18px;height:18px;color:var(--green);flex:0 0 auto}
@media(prefers-reduced-motion:reduce){.bmodal-card{transition:none}}

/* one green add button, full width */
.buyrow{grid-template-columns:1fr}
.buyrow .btn .ico{width:18px;height:18px}

/* ------------------------------------ checkout: the slot buttons, restored */
.daystrip{display:flex;gap:9px;overflow-x:auto;padding-block-end:6px;scrollbar-width:none;margin-block-end:16px}
.daystrip::-webkit-scrollbar{display:none}
.daychip{flex:0 0 auto;display:flex;flex-direction:column;align-items:center;gap:1px;cursor:pointer;
  border:1.5px solid var(--line);border-radius:14px;padding:9px 15px;min-width:76px;transition:.14s;position:relative}
.daychip input{position:absolute;opacity:0;pointer-events:none}
.daychip b{font-size:12px;font-weight:500;color:var(--mut)}
.daychip span{font-size:19px;font-weight:600;line-height:1.1}
.daychip small{font-size:10.5px;color:var(--mut)}
.daychip:hover{border-color:#CFE0D6}
.daychip:has(input:checked){border-color:var(--dark);background:var(--dark);color:#fff}
.daychip:has(input:checked) b,.daychip:has(input:checked) small{color:rgba(255,255,255,.82)}

.slotgroup{border:0;margin:0;padding:0 0 14px}
.slotgroup:last-child{padding-block-end:0}
.slotgroup legend{font-size:13px;font-weight:600;color:var(--mut);padding:0 0 9px}
.slotgroup.js{display:none}
.slotgroup.js.on{display:block}
.slotgroup.js.on legend{display:none}
.slotpills{display:grid;gap:9px;grid-template-columns:1fr}
@media(min-width:560px){.slotpills{grid-template-columns:1fr 1fr}}
.slotpill{display:flex;flex-direction:column;gap:2px;cursor:pointer;border:1.5px solid var(--line);
  border-radius:13px;padding:12px 15px;transition:.14s;position:relative}
.slotpill input{position:absolute;opacity:0;pointer-events:none}
.slotpill b{font-size:14px;font-weight:600}
.slotpill span{font-size:12px;color:var(--mut)}
.slotpill .tight{color:var(--warn);font-weight:600}
.slotpill:hover{border-color:#CFE0D6;background:#FBFDFB}
.slotpill:has(input:checked){border-color:var(--dark);background:#F1F6F2;box-shadow:inset 0 0 0 1px var(--dark)}

/* ===================================== THE BUY BAR =======================
   Price on one side; on the other, ONE control in two states — Add to basket
   until there is something in the basket, then a stepper holding the amount.
   The same idea as the cards, so the two never teach different habits.
   Base rules first; the phone overrides come after, because an identical
   selector written later beats one inside a media query. */
.buyactions{display:flex;align-items:center;gap:14px}
/* Desktop keeps the big price above; the bar's copy is for phones only,
   or the same number appears twice on the same screen. */
.ba-price{display:none;align-items:baseline;gap:4px;flex:0 0 auto;white-space:nowrap}
.ba-price b{font-size:24px;font-weight:700;letter-spacing:-.03em;font-variant-numeric:tabular-nums}
.ba-price i{font-style:normal;font-size:14px;font-weight:600}
.ba-price span{font-size:12.5px;color:var(--mut)}

.ba-ctl{position:relative;flex:1;min-width:0;height:52px}
.ba-add{position:absolute;inset:0;width:100%;transition:opacity .16s, transform .2s}
.ba-add .ico{width:18px;height:18px}
.ba-step{position:absolute;inset:0;display:flex;align-items:center;justify-content:space-between;
  border:1.5px solid var(--line);border-radius:var(--pill);background:#fff;padding:0 4px;
  opacity:0;pointer-events:none;transform:scaleX(.5);transform-origin:100% 50%;
  transition:transform .24s cubic-bezier(.22,.61,.36,1),opacity .15s}
[dir=rtl] .ba-step{transform-origin:0 50%}
.ba-step>*{opacity:0;transition:opacity .14s ease .07s}
.buyactions.has .ba-step{opacity:1;pointer-events:auto;transform:none}
.buyactions.has .ba-step>*{opacity:1}
.buyactions.has .ba-add{opacity:0;pointer-events:none;transform:scale(.94)}
.ba-step button{width:46px;height:46px;border-radius:var(--pill);display:grid;place-items:center;color:var(--ink)}
.ba-step button:hover{background:var(--tint)}
.ba-step button:last-child{background:var(--lime);color:var(--lime-ink)}
.ba-step button:last-child:hover{background:var(--lime-dk)}
.ba-step .ico{width:18px;height:18px;stroke-width:2.2}
.ba-qv{font-size:16px;font-weight:600;font-variant-numeric:tabular-nums;min-width:40px;text-align:center}
@media(prefers-reduced-motion:reduce){.ba-step,.ba-add,.ba-step>*{transition:none}}

/* ---------------------------------------------------------------- phone --
   A shorter photo, and the bar pinned to the bottom. Everything under it —
   origin, unit, SKU, the description — scrolls away, because that is
   reference you read once, not something you are waiting to press. */
@media(max-width:759px){
  .gal-main{aspect-ratio:auto;height:min(30vh,240px);padding:10px}
  .gal-main img{max-height:calc(min(30vh,240px) - 20px)}
  /* Shorter again in the sheet: the sheet is already only 88vh, so a photo
     sized for a full page pushes the name and price off the screen. */
  .pmodal-card{max-block-size:88vh;padding-block-start:4px}
  .pmodal-card .gal-main{height:min(22vh,180px)}
  .pmodal-card .gal-main img{max-height:calc(min(22vh,180px) - 20px)}
  .pdp{gap:12px}
  .pdp h1{font-size:22px}
  .pdp-short{font-size:14.5px;margin-block-end:12px}
  .badges{margin-block-end:12px}
  .badges li{padding:6px 12px;font-size:12px}
  .pdp-weightnote{margin-block-end:10px}
  .pmodal-card{padding-inline:16px}

  .pdp-price{display:none}            /* it lives in the bar down here */
  .ba-price{display:flex}

  /* FIXED to the window, not sticky inside the sheet: a sticky element can
     only stick within its own container, so on a short product it simply sat
     wherever the content ended. Fixed means it is always the last thing on
     screen, which is the point of it. */
  .buyactions{position:fixed;inset-inline:0;inset-block-end:0;z-index:99;gap:10px;background:#fff;
    padding-block:10px calc(10px + env(safe-area-inset-bottom));padding-inline:16px;
    border-block-start:1px solid var(--line);
    box-shadow:0 -12px 22px -12px rgba(15,60,45,.18)}
  /* room for it, so the last line of detail is still reachable */
  .pdp-info{padding-block-end:86px}
  .pmodal-card{padding-block-end:0}
  .ba-price b{font-size:21px}
  .ba-ctl{height:48px}
  .ba-add{font-size:14px;padding-inline:12px}
  .ba-add .ico{width:16px;height:16px}
  .ba-step button{width:42px;height:42px}
  .ba-qv{font-size:15px;min-width:34px}
  .modal-full{margin-block-end:8px}
}

/* the draft badge must not sit on top of the bar */
@media(max-width:899px){ .preview-dot{inset-block-end:84px} }
body:has(.pmodal.on) .preview-dot{display:none}

/* clear of the buy bar on a phone, and of nothing in particular on desktop */
@media(max-width:759px){
  body:has(.buyactions) .toast{inset-block-end:96px}
  body:has(.pmodal.on) .toast{inset-block-end:96px}
}

/* The toast fires at the same moment the basket pill appears, so it stands on
   top of it rather than across it. .haspill is set by paintPill(). */
body.haspill .toast{inset-block-end:94px}
@media(max-width:759px){
  body.haspill .toast{inset-block-end:92px}
  body.haspill:has(.aibtn) .toast{inset-block-end:154px}
}

/* ---------------------------------------------------------- a price cut --
   The old price is struck through beside the new one, and the card carries a
   small tag. Both are driven by compare_at_fils being higher than the price,
   so nothing says "sale" unless the numbers actually do. */
.pprice s,.pdp-price s,.ba-price s{color:var(--mut);font-weight:400;text-decoration:line-through}
.ba-price s{font-size:12px;margin-inline-start:4px}
.save-tag{position:absolute;inset-block-start:10px;inset-inline-start:10px;z-index:3;
  background:#D93A3A;color:#fff;font-size:11px;font-weight:700;letter-spacing:.01em;
  padding:4px 9px;border-radius:var(--pill)}
.pdp-save{display:inline-flex;align-items:center;gap:6px;background:#FDECEC;color:#B62E2E;
  font-size:12.5px;font-weight:600;padding:5px 12px;border-radius:var(--pill);margin-inline-start:8px}

/* ------------------------------------------------ payment, in the summary */
/* No border. Each method already draws its own card, so the box around them
   was a second frame around a set of frames. */
.paybox{border:0;border-radius:0;padding:12px 0;margin-block:12px 4px}
.paybox h3{font-size:12.5px;text-transform:uppercase;letter-spacing:.06em;color:var(--mut);
  font-weight:600;margin-block-end:10px}
.pay{display:flex;align-items:center;gap:11px;cursor:pointer;border:1.5px solid var(--line);
  border-radius:11px;padding:10px 12px;margin-block-end:8px;position:relative;transition:.14s}
.pay:last-of-type{margin-block-end:0}
.pay input{position:absolute;opacity:0;pointer-events:none}
.pay:hover{border-color:#CFE0D6}
.pay:has(input:checked){border-color:var(--dark);background:#F1F6F2}
.pay-ic{flex:0 0 auto;display:flex;align-items:center;gap:4px;color:var(--green)}
.pay-ic .ico{width:20px;height:20px}
.pay-ic.cards img{display:block;border-radius:3px}
.pay-t{display:flex;flex-direction:column;min-width:0}
.pay-t b{font-size:13.5px;font-weight:600}
.pay-t small{font-size:11.5px;color:var(--mut)}
.pay.locked{opacity:.45;pointer-events:none}
.pay-demo{display:flex;gap:8px;align-items:flex-start;background:#FFF7E6;border:1px solid #F0E0B8;
  color:#6B5312;border-radius:10px;padding:9px 11px;font-size:12px;line-height:1.5;margin:10px 0 0}
.pay-demo .ico{width:14px;height:14px;flex:0 0 auto;margin-block-start:2px}

/* ---- stock running short, said in the same words in all three places ---- */
.pshort{display:block;color:var(--warn);font-weight:600;font-size:12.5px;margin-block-start:2px}
.pane-warn{display:flex;gap:8px;align-items:flex-start;margin:0 0 10px;
  color:var(--warn);font-weight:600;font-size:13px;line-height:1.35}
.pane-warn svg{flex:0 0 auto;inline-size:18px;block-size:18px}
/* the warning is a fourth cell under the three the line already has */
.coline .coshort{grid-column:1 / -1;display:flex;align-items:center;gap:6px;
  color:var(--warn);font-weight:600;font-size:12.5px;margin-block-start:3px}
.coline .coshort svg{inline-size:16px;block-size:16px}
.paid-ok{display:flex;align-items:center;gap:6px;color:var(--ok,#1a7f4b);font-weight:700}
.paid-ok svg{inline-size:18px;block-size:18px}

/* ---- payment schemes, shown on our own checkout ---- */
.paymethods{display:flex;flex-wrap:wrap;gap:8px;margin:10px 0 2px;padding-inline-start:34px}
.pmeth{display:flex;align-items:center;gap:8px;padding:8px 12px;cursor:pointer;
  border:1.5px solid var(--line);border-radius:12px;background:#fff;font-size:13.5px;font-weight:600}
.pmeth img{display:block;block-size:22px;inline-size:auto}
.pmeth input{accent-color:var(--dark)}
.pmeth:has(input:checked){border-color:var(--dark);box-shadow:0 0 0 1px var(--dark) inset}
@media (max-width:520px){.paymethods{padding-inline-start:0}.pmeth{flex:1 1 calc(50% - 8px)}}

/* ---- an order that still owes money ---- */
.done-top .tick.warn{background:#FFF3D6;color:#8A5A00}
.done.unpaid .done-top .btn{margin-block-start:14px}
.done.unpaid .done-top .muted{margin-block-start:8px}

/* ---- one flat payment list: the scheme logo sits where the icon did ---- */
.pay .pay-ic img{display:block;block-size:24px;inline-size:auto}
.pay.locked{opacity:.5}
/* the unfinished order, offered back */
.unfinished{border:1.5px solid var(--line);border-radius:var(--r);padding:22px;text-align:center}
.unfinished h2{display:flex;align-items:center;justify-content:center;gap:8px;margin:0 0 6px;font-size:19px}
.unfinished-do{display:flex;flex-wrap:wrap;gap:10px;justify-content:center;margin:14px 0 8px}
.unfinished-do form{margin:0}
.linkbtn{background:none;border:0;padding:0;color:var(--mut);text-decoration:underline;
  cursor:pointer;font:inherit;font-size:13.5px}
.done-alt{margin-block-start:10px}

/* ---- the card fields, drawn by the gateway inside our own checkout ---- */
.cardbox{border:1.5px solid var(--line);border-radius:14px;padding:14px;margin:2px 0 10px;background:#fff}
.cardnote{display:flex;gap:7px;align-items:flex-start;margin:10px 0 0;
  color:var(--mut);font-size:12.5px;line-height:1.4}
.cardnote svg{flex:0 0 auto;inline-size:16px;block-size:16px}
.carderr{margin:10px 0 0;color:#c0392b;font-weight:600;font-size:13px}

/* ---- saving a card, and the cards already saved ---- */
.savecard{display:flex;align-items:center;gap:9px;margin-block-start:12px;
  font-size:13.5px;font-weight:600;cursor:pointer}
.savecard input{inline-size:17px;block-size:17px;accent-color:var(--dark)}
.cardnote.sm{font-size:12px;margin-block-start:5px;padding-inline-start:26px}
.pay[data-saved] .pay-ic svg{inline-size:22px;block-size:22px;color:var(--mut)}

/* ---- saved cards on the account page ---- */
.cardlist{display:flex;flex-direction:column;gap:8px;margin:10px 0}
.cardrow{display:flex;align-items:center;gap:10px;padding:12px 14px;
  border:1.5px solid var(--line);border-radius:12px;background:#fff}
.cardrow form{margin-inline-start:auto}

/* ---- the customer we already know, shown back instead of asked again ---- */
.mecard{display:flex;align-items:center;gap:14px;border:1.5px solid var(--line);
  border-radius:14px;padding:13px 15px;margin-bottom:6px;background:#fff}
.mecard div{display:flex;flex-direction:column;gap:2px;min-width:0}
.mecard b{font-size:15px}
.mecard span{color:var(--mut);font-size:13.5px}
.linkish{margin-inline-start:auto;background:none;border:0;padding:0;font:inherit;
  font-size:13.5px;font-weight:700;color:var(--dark);text-decoration:underline;cursor:pointer}

/* ---- points this basket earns ---- */
.earnnote{display:flex;gap:8px;align-items:flex-start;margin:10px 0 0;
  font-size:13px;font-weight:600;color:var(--dark)}
.earnnote svg{flex:0 0 auto;inline-size:16px;block-size:16px;color:var(--dark)}
.earnnote a{text-decoration:underline;font-weight:700}

/* ---- how close this basket is to free delivery ---- */
.freebar{margin:0 0 12px}
.freebar-t{display:flex;align-items:center;gap:7px;font-size:12.5px;font-weight:700;
  color:var(--dark);margin-bottom:7px}
.freebar-t svg{inline-size:16px;block-size:16px}
.freebar-track{block-size:7px;border-radius:99px;background:#eaefe9;overflow:hidden}
.freebar-track i{display:block;block-size:100%;border-radius:99px;background:var(--dark);
  inline-size:0;transition:inline-size .35s ease}
.freebar.done .freebar-t{color:#1a7f4b}
.freebar.done .freebar-track i{background:var(--lime)}
@media(prefers-reduced-motion:reduce){.freebar-track i{transition:none}}

/* ---- "you may also like", between the basket lines and the footer ---- */
/* A strip, not a shelf. It sits between the basket and the checkout button, so
   every pixel it takes is a pixel of basket somebody cannot see — it was taking
   half the pane on a phone. */
.paneal{flex:0 0 auto;border-block-start:1px solid var(--line);padding:8px 18px 0;background:#fff}
.paneal h3{margin:0 0 7px;font-size:11.5px;font-weight:700;color:var(--mut);
  text-transform:uppercase;letter-spacing:.05em}
.paneal-row{display:flex;gap:10px;overflow-x:auto;padding-block-end:10px;
  scroll-snap-type:x mandatory;-webkit-overflow-scrolling:touch}
.paneal-row::-webkit-scrollbar{block-size:0}
.alcard{flex:0 0 128px;scroll-snap-align:start;border:1.5px solid var(--line);
  border-radius:12px;padding:8px;display:flex;flex-direction:column;gap:6px}
.alimg{display:block;aspect-ratio:1;border-radius:8px;overflow:hidden;background:#f6f8f6}
/* the pane's copy is deliberately smaller than the assistant's, and white
   throughout: the grey image tile reads as a placeholder that never loaded
   when it sits on the pane's own white. */
.paneal .alcard{flex:0 0 92px;min-inline-size:0;padding:5px;gap:3px;background:#fff}
.paneal .alimg{background:#fff}
.paneal .alimg{aspect-ratio:1/1}
.paneal .alname{font-size:11px;-webkit-line-clamp:1}
.paneal .alprice{font-size:11.5px}
.paneal .alplus{inline-size:24px;block-size:24px;display:grid;place-items:center;
  padding:0;line-height:0}
.paneal .alplus svg{inline-size:13px;block-size:13px;display:block}
.paneal .alstep{padding:1px}
.paneal .alstep button{inline-size:18px;block-size:18px;font-size:13px}
.paneal .alstep span{min-inline-size:14px;font-size:11px}
.paneal .paneal-row{padding-block-end:6px}
.alimg img{inline-size:100%;block-size:100%;object-fit:contain}
.alname{font-size:12px;font-weight:600;line-height:1.3;display:-webkit-box;
  -webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.alfoot{display:flex;align-items:center;gap:6px;margin-block-start:auto;min-inline-size:0}
.alfoot > .alprice{min-inline-size:0}
/* Not bold. On a card this small the name is what you are reading and the
   price is what you are checking — two bold things side by side means neither
   leads. */
.alprice{font-size:12.5px;font-weight:500;white-space:nowrap}
.alplus{margin-inline-start:auto;inline-size:26px;block-size:26px;border-radius:50%;
  border:0;background:var(--lime);color:var(--lime-ink,#14241C);display:grid;place-items:center;cursor:pointer}
.alplus svg{inline-size:15px;block-size:15px;stroke-width:2.6}

/* ==========================================================================
   The food assistant.

   On a wide screen it docks to the side and the page makes room for it, so
   somebody can keep browsing while they talk — a floating box that covers the
   products is useless for a conversation about products. On a phone there is no
   "beside", so it takes the whole screen like any other chat app.
   ========================================================================== */

.aibtn{position:fixed;inset-block-end:18px;inset-inline-end:18px;z-index:80;
  display:flex;align-items:center;gap:7px;padding:11px 16px;border:0;border-radius:99px;
  background:var(--dark);color:#fff;font:inherit;font-weight:700;font-size:14px;cursor:pointer;
  box-shadow:0 8px 24px rgba(10,40,25,.26);
  transition:inset-inline-end .28s ease, inset-block-end .22s ease}
.aibtn svg{inline-size:19px;block-size:19px;color:var(--lime)}
.aibtn:hover{transform:translateY(-1px)}

.aipanel{position:fixed;z-index:81;display:flex;flex-direction:column;background:#fff;
  inset-block:0;inset-inline-end:0;inline-size:var(--ai-w);
  border-inline-start:1px solid var(--line);
  box-shadow:-18px 0 50px rgba(10,40,25,.10);
  transform:translateX(100%);transition:transform .28s ease}
[dir=rtl] .aipanel{transform:translateX(-100%)}
.aipanel.on{transform:none}

:root{--ai-w:380px}

/* the page steps aside rather than being covered */
@media (min-width:1024px){
  body.aiopen{padding-inline-end:var(--ai-w)}
  body.aiopen .aibtn{inset-inline-end:calc(var(--ai-w) + 18px)}
}

.aipanel header{display:flex;align-items:center;gap:10px;padding:16px 18px;
  border-block-end:1px solid var(--line);flex:0 0 auto}
.aipanel header b{display:flex;align-items:center;gap:8px;font-size:15.5px}
.aipanel header svg{inline-size:18px;block-size:18px;color:var(--dark)}
.aix{margin-inline-start:auto;background:none;border:0;padding:6px;cursor:pointer;
  color:var(--mut);border-radius:8px;line-height:0}
.aix:hover{background:#f2f6f3;color:var(--ink)}

.aibody{flex:1 1 auto;min-block-size:0;overflow-y:auto;padding:16px 18px;
  display:flex;flex-direction:column;gap:10px}
.aibody > *{flex:0 0 auto}

.aimsg p{margin:0;padding:11px 14px;border-radius:15px;font-size:14.5px;line-height:1.5;
  white-space:pre-wrap;overflow-wrap:anywhere}
.aimsg.bot p{background:#f2f6f3;border-start-start-radius:5px}
.aimsg.me{align-self:flex-end;max-inline-size:85%}
.aimsg.me p{background:var(--dark);color:#fff;border-end-end-radius:5px}
.aimsg.typing p{color:var(--mut);letter-spacing:.18em}

.aichips{display:flex;flex-wrap:wrap;gap:7px}
.aichips button{border:1.5px solid var(--line);background:#fff;border-radius:99px;
  padding:8px 14px;font:inherit;font-size:13px;font-weight:600;cursor:pointer;
  transition:border-color .15s,background .15s}
.aichips button:hover{border-color:var(--dark);background:#f7faf8}
.aichips button.go{background:var(--dark);color:#fff;border-color:var(--dark)}

.aicards{display:flex;gap:9px;overflow-x:auto;padding-block-end:6px}
/* Wide enough for the stepper that replaces the + once something is added.
 *
 * flex-basis alone did not hold the card at 134px: a flex item's min-width is
 * `auto`, which means "no narrower than your content", and price + stepper on
 * one row is wider than that. So the card grew the moment you tapped +, and
 * every card after it shifted along. The basis now fits the widest state and
 * min-inline-size:0 stops the content overriding it either way. */
.aicards .alcard{flex:0 0 150px;min-inline-size:0;min-block-size:172px}
.aicards .alstep button{inline-size:18px;block-size:18px;font-size:14px}
.aicards .alstep span{min-inline-size:15px}

/* ---- the composer ---- */
.aiform{display:flex;gap:9px;align-items:center;padding:12px 16px 8px;
  border-block-start:1px solid var(--line);flex:0 0 auto;background:#fff}
.aiform input{flex:1;min-inline-size:0;block-size:46px;padding:0 16px;
  border:1.5px solid var(--line);border-radius:99px;background:#fff;
  font:inherit;font-size:14.5px;color:var(--ink);outline:none;
  transition:border-color .15s,box-shadow .15s}
.aiform input::placeholder{color:var(--mut)}
.aiform input:focus{border-color:var(--dark);box-shadow:0 0 0 3px rgba(14,74,66,.10)}
.aiform button{inline-size:46px;block-size:46px;flex:0 0 46px;border:0;border-radius:50%;
  background:var(--lime);color:var(--lime-ink,#14241C);display:grid;place-items:center;
  cursor:pointer;transition:transform .12s}
.aiform button:hover{transform:scale(1.05)}
.aiform button svg{inline-size:19px;block-size:19px;stroke-width:2.2}
.aifoot{margin:0;padding:0 18px 14px;color:var(--mut);font-size:11.5px;line-height:1.45;flex:0 0 auto}

/* ---- a phone gets the whole screen ---- */
@media (max-width:1023px){
  .aipanel{inset:0;inline-size:100%;border-inline-start:0;
    transform:translateY(100%);border-radius:0}
  [dir=rtl] .aipanel{transform:translateY(100%)}
  .aipanel.on{transform:none}
  .aipanel header{padding-block-start:max(16px,env(safe-area-inset-top))}
  .aifoot{padding-block-end:max(14px,env(safe-area-inset-bottom))}
  .aibtn{inset-block-end:14px;inset-inline-end:14px}
  body.aiopen{overflow:hidden}
}

/* ---- the basket, shown in the assistant as a receipt ---- */
.aisum{border:1.5px solid var(--line);border-radius:14px;overflow:hidden;background:#fff}
.aisum-r{display:flex;align-items:center;gap:10px;padding:9px 12px;border-block-end:1px solid var(--line2)}
.aisum-r img{inline-size:34px;block-size:34px;border-radius:8px;object-fit:contain;background:#f6f8f6;flex:0 0 auto}
/* The text block only. Without :not(), the stepper — also a direct child div —
   inherited flex-direction:column and stacked − / qty / + vertically. */
.aisum-r > div:not(.alstep){display:flex;flex-direction:column;min-width:0;flex:1}
.aisum-r b{font-size:13.5px;font-weight:700;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.aisum-r span{font-size:12px;color:var(--mut)}
.aisum-r i{font-style:normal;font-weight:700;font-size:13.5px;white-space:nowrap;
  font-variant-numeric:tabular-nums}
.aisum-f{display:flex;justify-content:space-between;gap:10px;padding:8px 12px;
  font-size:13px;color:var(--mut);background:#fafcfb}
/* Only the amount that actually leaves their account is bold. When every row
   is bold, none of them is — the eye has nowhere to land. */
.aisum-f b{font-variant-numeric:tabular-nums;color:var(--ink);font-weight:500;text-align:end}
.aisum-f.strong{font-size:15px;color:var(--ink);border-block-start:1px solid var(--line)}
.aisum-f.strong span,.aisum-f.strong b{font-weight:800}

/* the stepper that replaces + on an assistant card */
.alstep{margin-inline-start:auto;display:flex;align-items:center;gap:2px;
  background:var(--lime);border-radius:99px;padding:2px;flex:0 0 auto}
.alstep button{inline-size:20px;block-size:20px;border:0;background:none;cursor:pointer;
  font:inherit;font-weight:800;font-size:15px;line-height:1;color:var(--lime-ink,#14241C)}
.alstep span{min-inline-size:18px;text-align:center;font-size:12px;font-weight:800}
.aichips button.go{background:var(--dark);color:#fff;border-color:var(--dark)}
/* a stepper sized for a summary row rather than a card */
.aisum-r .alstep.sm{margin-inline-start:8px;padding:2px;flex:0 0 auto;
  flex-direction:row;align-items:center}
.aisum-r .alstep.sm button{inline-size:19px;block-size:19px;font-size:14px}
.aisum-r .alstep.sm span{min-inline-size:16px;font-size:11.5px}

/* The side pane takes 380px of the page but not of the viewport, so the grid's
   width-based breakpoints keep their column count and the cards get squeezed.
   One column comes out at each step while the panel is open. */
@media(min-width:980px) { body.aiopen .grid{grid-template-columns:repeat(4,1fr)} }
@media(min-width:1400px){ body.aiopen .main.wide .grid{grid-template-columns:repeat(5,1fr)} }
@media(min-width:1750px){ body.aiopen .main.wide .grid{grid-template-columns:repeat(6,1fr)} }
@media(min-width:2100px){ body.aiopen .main.wide .grid{grid-template-columns:repeat(7,1fr)} }

/* "Start again" sits beside the close button */
.ainew{background:none;border:0;padding:6px;cursor:pointer;color:var(--mut);
  border-radius:8px;line-height:0;margin-inline-start:auto}
.ainew:hover{background:#f2f6f3;color:var(--ink)}
.ainew + .aix{margin-inline-start:0}
.aigate{border:1.5px solid var(--line);border-radius:14px;padding:14px;text-align:center}
.aigate p{margin:0 0 10px;font-size:13.5px;color:var(--mut)}
/* redeeming points from the checkout */
.redeemrow{display:flex;align-items:center;gap:9px;padding:9px 0;font-size:13px;font-weight:600}
.redeemrow span{display:flex;align-items:center;gap:7px;color:var(--dark)}
.redeemrow svg{inline-size:16px;block-size:16px}
.redeemrow button{margin-inline-start:auto}
/* The address, inside the same card as the contact. A rule between them, not
   a second box: it is one delivery being confirmed. */
.mecard-addr{margin-block-start:7px;padding-block-start:7px;
  border-block-start:1px solid var(--line)}
.mecard-addr + .mecard-addr{margin-block-start:0;padding-block-start:0;border-block-start:0}

/* ---- the redeem dialog ---- */
.rmodal{position:fixed;inset:0;z-index:1200;display:grid;place-items:center;padding:18px}
/* The dialog is moved to <body> when it opens (see shop.js). It is written
   inside the order summary, which is position:sticky — and a sticky element
   creates its own stacking context, so a z-index set in here could never lift
   the dialog above the footer painted after it. Raising the number does not
   fix that; leaving the context does. */
.rmodal-scrim{position:absolute;inset:0;background:rgba(9,32,26,.55);backdrop-filter:blur(2px)}
/* The sign-in dialog holds a whole form, so it needs more room than the
   points one it shares a shell with. */
.joinmodal .rmodal-card{inline-size:min(420px,100%);text-align:start}
.joinmodal .rmodal-have{text-align:start}
.joinmodal .joinbox{margin:0;border:0;padding:0;background:none;box-shadow:none}
.rmodal-card{position:relative;inline-size:min(360px,100%);
  max-block-size:min(86dvh,720px);overflow-y:auto;overscroll-behavior:contain;background:#fff;
  border-radius:18px;padding:24px 22px 20px;text-align:center;
  box-shadow:0 24px 60px rgba(9,32,26,.3)}
.rmodal-card h3{display:flex;align-items:center;justify-content:center;gap:8px;
  margin:0 0 6px;font-size:17px}
.rmodal-card h3 svg{inline-size:18px;block-size:18px;color:var(--dark)}
.rmodal-x{position:absolute;inset-block-start:10px;inset-inline-end:10px;inline-size:30px;
  block-size:30px;border:0;background:none;cursor:pointer;color:var(--mut);border-radius:50%;
  display:grid;place-items:center}
.rmodal-x:hover{background:#f2f6f3;color:var(--ink)}
.rmodal-x svg{inline-size:15px;block-size:15px}
.rmodal-have{margin:0 0 16px;font-size:12.5px;color:var(--mut)}

.rmodal-pick{display:flex;align-items:center;justify-content:center;gap:10px}
.rstep{inline-size:38px;block-size:38px;border:1.5px solid var(--line);background:#fff;
  border-radius:50%;font-size:19px;font-weight:700;line-height:1;cursor:pointer;color:var(--dark);
  flex:0 0 auto}
.rstep:hover:not(:disabled){border-color:var(--dark);background:#f3f8f4}
.rstep:disabled{opacity:.35;cursor:not-allowed}
.redeemn{inline-size:104px;padding:8px;font-size:18px;font-weight:800;text-align:center;
  font-variant-numeric:tabular-nums;border:1.5px solid var(--line);border-radius:11px;
  background:#fff;flex:0 0 auto;-moz-appearance:textfield}
.redeemn::-webkit-outer-spin-button,.redeemn::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
.redeemn:focus{border-color:var(--dark);outline:none}

.rmodal-worth{margin:14px 0 16px;font-size:13.5px;color:var(--mut)}
.rmodal-worth b{font-size:19px;color:var(--dark);font-variant-numeric:tabular-nums;
  display:block;margin-block-end:2px}
.rmodal-note{margin:12px 0 0;font-size:11.5px;color:var(--mut);line-height:1.5}

/* The reason a number is refused, said beside the number rather than as a
   flash at the top of a page the customer is not looking at. */
.rmodal-bad{margin:12px 0 0;font-size:12.5px;font-weight:600;color:#B3261E;
  background:#FDECEA;border-radius:10px;padding:8px 10px;text-align:start}
.rmodal.invalid .rmodal-worth{display:none}
.rmodal-card .btn[disabled]{opacity:.45;pointer-events:none}
/* wallet as a partial payment, inside the payment box */
.walletpart{display:flex;gap:11px;align-items:flex-start;padding:13px 15px;margin-block:2px 8px;
  border:1.5px solid var(--line);border-radius:14px;cursor:pointer}
.walletpart input{inline-size:18px;block-size:18px;margin-block-start:2px;accent-color:var(--dark)}
.walletpart b{display:block;font-size:14.5px}
.walletpart small{display:block;color:var(--mut);font-size:12.5px;margin-block-start:2px}
.walletpart:has(input:checked){border-color:var(--dark);background:#f7faf8}

/* ---- subscribe ----
   Back to the quiet version. The bordered, tinted, badged treatment shouted
   at somebody who is trying to finish paying — it read as an advert dropped
   into the middle of their order. Only the info panel is new. */
.rb-t b{display:flex;align-items:center;gap:7px;flex-wrap:wrap}
.rb-t b svg{inline-size:16px;block-size:16px;color:var(--dark)}
.rb-t small{display:block;color:var(--mut);font-size:13px;margin-block-start:3px}
.rb-tag{display:none}
/* The help button sits beside the heading it explains; the NEW badge has the
   corner. A badge labels the whole box, a help button belongs to its subject. */
.rb-t b{display:flex;align-items:center;gap:6px}
.rb-t{padding-inline-end:46px}
.rb-i{inline-size:22px;block-size:22px;flex:0 0 auto;
  border:0;border-radius:50%;background:none;color:var(--mut);display:grid;place-items:center;cursor:pointer}
.rb-i:hover{color:var(--dark)}
.rb-i svg{inline-size:14px;block-size:14px}
.rb-i.on{color:var(--dark)}
/* The subscription explainer, as a dialog. A fold here shoved the payment box
   and the Pay button down the page at the moment somebody was reading them. */
/* Same trap as the coupon pane: .sum is sticky, so it is a stacking context of
   its own and the page header (z-index 50 at the root) would paint over this.
   The summary is lifted for as long as the dialog is up. */
.sum:has(.submodal.on){z-index:200}
.submodal{position:fixed;inset:0;z-index:130;display:grid;place-items:center;padding:18px}
.submodal-scrim{position:absolute;inset:0;background:rgba(10,30,20,.45)}
.submodal-card{position:relative;background:#fff;border-radius:16px;padding:18px 20px 20px;
  inline-size:min(440px,100%);max-block-size:min(80vh,620px);overflow:auto;
  box-shadow:0 24px 60px rgba(10,40,25,.28);
  animation:submodin .2s cubic-bezier(.22,.61,.36,1)}
@keyframes submodin{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}
@media(prefers-reduced-motion:reduce){.submodal-card{animation:none}}
.submodal-head{display:flex;align-items:center;gap:12px;margin-block-end:4px}
.submodal-head h3{font-size:16px;flex:1;min-width:0}
.submodal-x{inline-size:30px;block-size:30px;border-radius:var(--pill);display:grid;place-items:center;
  background:var(--tint);color:var(--mut);flex:0 0 auto}
.submodal-x:hover{background:#E7EFE9;color:var(--dark)}
.submodal-x .ico{inline-size:15px;block-size:15px}
.submodal dt{font-size:13px;font-weight:700;margin-block-start:13px}
.submodal dd{margin:3px 0 0;color:var(--mut);font-size:12.5px;line-height:1.5}

/* A quiet badge, not a shout. In the corner it labels the box; the rule below
   keeps it usable anywhere else it appears inline. */
.repeatbox > .newtag{position:absolute;inset-block-start:11px;inset-inline-end:12px;margin:0}
.newtag{display:inline-block;margin-inline-start:7px;vertical-align:1px;
  background:var(--lime);color:var(--lime-ink,#14241C);
  font-size:9.5px;font-weight:800;font-style:normal;letter-spacing:.08em;
  padding:2px 6px;border-radius:5px;line-height:1}

/* the money block, now below the payment methods */
/* Section rules run the full width of the card.
 *
 * .sum pads 18px, so these cancel it and pad themselves back — the same trick
 * the sign-in band uses. A divider that stops short of the edge reads as the
 * underline of the row above it; one that crosses the card reads as a break
 * between sections, which is what these are. */
.sumtotals{border-block-start:1px solid var(--line);margin:16px -18px 0;padding:14px 18px 0}
.sumtotals .srow{padding-block:5px}
.sumtotals .srow.tot{margin:8px -18px 0;padding:11px 18px 0;border-block-start:1px solid var(--line)}
.sumtotals .earnnote{margin-block-start:10px}
.sumtotals .redeemrow{border-block:1px dashed var(--line);margin-block:8px;padding-block:10px}

/* ---- the basket pill that follows you down the page ---- */
.gocheck{position:fixed;inset-block-end:28px;inset-inline:0;z-index:70;
  margin-inline:auto;inline-size:fit-content;max-inline-size:calc(100% - 32px);
  display:flex;align-items:center;gap:11px;
  padding:12px 20px;border-radius:99px;background:var(--dark);color:#fff;
  font-weight:700;font-size:14.5px;white-space:nowrap;
  box-shadow:0 10px 30px rgba(10,40,25,.30);
  animation:pillin .26s cubic-bezier(.22,.61,.36,1)}
.gocheck:hover{transform:translateY(-1px)}
.gc-n{display:grid;place-items:center;min-inline-size:22px;block-size:22px;padding-inline:6px;
  border-radius:99px;background:var(--lime);color:var(--lime-ink,#14241C);font-size:12.5px;font-weight:800}
.gc-v{font-variant-numeric:tabular-nums;opacity:.85}
@keyframes pillin{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}
@media(prefers-reduced-motion:reduce){.gocheck{animation:none}}
/* Centred, full stop.
 *
 * Two attempts to shift it clear of the assistant's button both broke the
 * centring, because `margin-inline:auto` only centres while BOTH margins are
 * auto: fix one and the auto side swallows all the slack, throwing the pill to
 * the opposite edge. On a wide screen there is nothing to dodge anyway — the
 * assistant sits in the bottom-right corner and the pill is a narrow thing in
 * the middle. The phone rule below lifts it instead, which costs no centring. */

/* Stays a pill on a phone: centred, only as wide as its own words. */
@media(max-width:759px){
  .gocheck{inset-block-end:20px}
}

/* The bottom-right corner stacks ABOVE the pill, not the other way round.
 *
 * The pill is the thing being acted on — it appears because something was just
 * added — so it keeps the bottom edge and everything else steps up out of its
 * way. Only while it is showing; with an empty basket the corner sits where it
 * always did. `haspill` is set by paintPill(). */
body.haspill .aibtn{inset-block-end:86px}
body.haspill .preview-dot{inset-block-end:146px}
@media(max-width:759px){
  body.haspill .aibtn{inset-block-end:78px}
  body.haspill .preview-dot{inset-block-end:138px}
}
@supports(padding:env(safe-area-inset-bottom)){
  body.haspill .aibtn{inset-block-end:calc(86px + env(safe-area-inset-bottom))}
  body.haspill .preview-dot{inset-block-end:calc(146px + env(safe-area-inset-bottom))}
  @media(max-width:759px){
    body.haspill .aibtn{inset-block-end:calc(78px + env(safe-area-inset-bottom))}
    body.haspill .preview-dot{inset-block-end:calc(138px + env(safe-area-inset-bottom))}
  }
}
/* safe area on phones with a home bar */
@supports(padding:env(safe-area-inset-bottom)){
  .gocheck{inset-block-end:calc(28px + env(safe-area-inset-bottom))}
  @media(max-width:759px){
    .gocheck{inset-block-end:calc(20px + env(safe-area-inset-bottom))}
  }
}


/* ---- checkout: four steps, one box ----
   They are one errand — how, when, where, and what to do if something is
   short — and four separate cards made a short form look like a long one. */
.cocols > .cobox{padding:0}
.costep{padding:20px;border-block-start:1px solid var(--line)}
.costep:first-child{border-block-start:0}
.costep > h2{font-size:17px;display:flex;align-items:center;gap:11px;margin-block-end:15px}
.costep .num{width:26px;height:26px;border-radius:var(--pill);background:var(--dark);color:#fff;
  display:grid;place-items:center;font-size:13px;font-weight:700;flex:0 0 auto}
@media(max-width:559px){ .costep{padding:16px} }

/* House, floor and flat are one thought and three short answers. */
.f3,.f2{display:grid;gap:13px;grid-template-columns:1fr}
@media(min-width:620px){
  .f3{grid-column:1/-1;grid-template-columns:2fr 1fr 1fr}
  .f2{grid-column:1/-1;grid-template-columns:1fr 1fr}
}
/* On a phone the house keeps the full width and floor and flat halve the row
   below it. Governorate and area pair the same way. Everything else — name,
   mobile, block, street — stays full width, because halving a field people
   type a real answer into just makes it harder to read back. */
@media(max-width:619px){
  .f3{grid-template-columns:1fr 1fr}
  .f3 > :first-child{grid-column:1/-1}
  .f2{grid-template-columns:1fr 1fr}
}

/* The earning line is a footnote to the total, not a label on the button. */
.earnnote{margin-block:12px 16px}

/* ======================================================== COUPONS ========
   A discount has to say which code produced it and offer a way to take it
   off again. A discount nobody can remove is a trap: the wrong code gets
   applied, or a good one gets spent on a small basket, and the only way back
   is clearing the session. */
.couponrow{flex-wrap:wrap}
.couponrow > span{display:flex;align-items:center;gap:6px;min-width:0}
.couponrow .ico{inline-size:14px;block-size:14px;color:var(--green);flex:0 0 auto}
.couponrow .ccode{font-variant-numeric:tabular-nums;letter-spacing:.04em}
.couponrow .cx{inline-size:19px;block-size:19px;border-radius:var(--pill);display:grid;place-items:center;
  background:var(--tint);color:var(--mut);margin-inline-start:3px;flex:0 0 auto}
.couponrow .cx:hover{background:#F3DADA;color:var(--danger)}
.couponrow .cx .ico{inline-size:9px;block-size:9px;color:currentColor}
.couponrow .crx{flex-basis:100%;color:var(--warn);font-size:11.5px;margin-block-start:3px}

/* The coupon controls lead the summary, so they need a line under them: a
   code field hard against Subtotal reads as part of the arithmetic. */
.couponadd{display:flex;gap:8px;padding-block:4px 10px}
.couponmine{border-block-end:1px solid var(--line);margin-inline:-18px;padding:0 18px 12px}
.cptray + .couponmine{margin-block-start:0}
.couponadd input{flex:1;min-width:0;block-size:38px;border:1.5px solid var(--line);border-radius:10px;
  padding-inline:12px;font-size:13.5px;text-transform:uppercase;letter-spacing:.06em;background:#fff}
.couponadd input:focus{border-color:var(--green);outline:none}
.couponadd input::placeholder{text-transform:none;letter-spacing:0;color:var(--mut)}
.couponadd .btn{flex:0 0 auto;block-size:38px}
/* The coupons they hold, as a row you push along. A grid would push the
   total off the screen the moment somebody collects a few; a row stays one
   line high however many there are. */
.cptray{display:flex;gap:8px;overflow-x:auto;padding-block:2px 10px;
  scroll-snap-type:x proximity;-webkit-overflow-scrolling:touch;
  scrollbar-width:thin;scrollbar-color:var(--line) transparent}
.cptray::-webkit-scrollbar{block-size:5px}
.cptray::-webkit-scrollbar-thumb{background:var(--line);border-radius:99px}
.cpchip{flex:0 0 auto;scroll-snap-align:start;text-align:start;
  display:flex;flex-direction:column;gap:0;min-inline-size:0;
  border:1.5px dashed #CFE0D6;border-radius:10px;padding:6px 11px;background:#fff;
  transition:.14s;cursor:pointer}
.cpchip:hover:not(.off){border-color:var(--green);border-style:solid;background:var(--tint);
  transform:translateY(-1px)}
.cpchip .cc-v{font-size:13.5px;font-weight:800;color:var(--dark);line-height:1.25}
.cpchip .cc-c{font-size:10.5px;font-weight:700;letter-spacing:.07em;color:var(--green);line-height:1.25}
.cpchip .cc-n{font-size:10px;color:var(--mut);line-height:1.3;margin-block-start:1px;
  max-inline-size:150px;white-space:normal}
.cpchip.off{opacity:.55;cursor:not-allowed;border-style:dotted}
.cpchip.off .cc-v,.cpchip.off .cc-c{color:var(--mut)}

.couponmine{margin:-4px -18px 8px;font-size:12px}
.couponmine a,.couponmine button{color:var(--green);text-decoration:underline;font-weight:600;
  font-size:12px;background:none;padding:0}
.couponmine button{cursor:pointer}

/* ---- every coupon they hold, without leaving the checkout ----
   Sending somebody to their account page mid-payment is asking them to
   abandon the order to find out whether they have a reason not to. A side
   pane on a wide screen, a sheet from the bottom on a phone: both keep the
   basket where it was. */
/* .sum is position:sticky, which makes a stacking context — so the pane's
   z-index only ever counted INSIDE it, and the sticky header (z-index 50 at the
   root) painted straight over the top of the pane. Lifting the whole summary
   while the pane is open is what puts it above the header. */
.sum:has(.cpmodal.on){z-index:200}
.cpmodal{position:fixed;inset:0;z-index:135;display:flex}
.cpmodal-scrim{position:absolute;inset:0;background:rgba(10,30,20,.45)}
.cpmodal-card{position:relative;margin-inline-start:auto;background:#fff;
  inline-size:min(420px,100%);block-size:100%;display:flex;flex-direction:column;
  box-shadow:-18px 0 50px rgba(10,40,25,.22);
  animation:cpslide .24s cubic-bezier(.22,.61,.36,1)}
@keyframes cpslide{from{transform:translateX(100%)}to{transform:none}}
[dir=rtl] .cpmodal-card{animation-name:cpslidertl}
@keyframes cpslidertl{from{transform:translateX(-100%)}to{transform:none}}
/* Out the same way it came in. Vanishing is not closing. */
.cpmodal.closing .cpmodal-card{animation:cpslideout .2s ease-in forwards}
.cpmodal.closing .cpmodal-scrim{animation:cpfade .2s ease-in forwards}
@keyframes cpslideout{to{transform:translateX(100%)}}
[dir=rtl] .cpmodal.closing .cpmodal-card{animation-name:cpslideoutrtl}
@keyframes cpslideoutrtl{to{transform:translateX(-100%)}}
@keyframes cpfade{to{opacity:0}}
.cpmodal-head{display:flex;align-items:center;gap:12px;padding:16px 18px;
  border-block-end:1px solid var(--line)}
.cpmodal-head h3{font-size:16px;flex:1;min-width:0}
.cpmodal-x{inline-size:30px;block-size:30px;border-radius:var(--pill);display:grid;place-items:center;
  background:var(--tint);color:var(--mut);flex:0 0 auto}
.cpmodal-x:hover{background:#E7EFE9;color:var(--dark)}
.cpmodal-x .ico{inline-size:14px;block-size:14px}
.cpmodal-body{flex:1;overflow:auto;padding:12px 18px 20px;display:grid;gap:9px;align-content:start}

.cprow{display:flex;align-items:center;gap:12px;border:1px solid var(--line);
  border-radius:12px;padding:11px 13px}
.cprow .cpr-l{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}
.cprow .cpr-l b{font-size:15px;color:var(--dark);line-height:1.2}
.cprow .cpr-code{font-size:11.5px;font-weight:700;letter-spacing:.07em;color:var(--green)}
.cprow .cpr-l small{font-size:11px;color:var(--mut)}
.cprow .cpr-l em{font-size:11px;color:var(--warn);font-style:normal;margin-block-start:2px}
.cprow .cpr-r{flex:0 0 auto}
.cprow .cpr-st{font-size:11.5px;color:var(--mut)}
.cprow.applied{border-color:var(--green);background:#F1F6F2}
.cprow.used,.cprow.expired{opacity:.55;background:var(--tint)}
.cprow.used .cpr-l b,.cprow.expired .cpr-l b{text-decoration:line-through}

@media(max-width:559px){
  /* A sheet from the bottom: a side pane on a phone is just a page. */
  .cpmodal-card{margin:auto 0 0;inline-size:100%;block-size:min(78vh,620px);
    border-start-start-radius:18px;border-start-end-radius:18px;
    animation-name:cpsheet}
  @keyframes cpsheet{from{transform:translateY(100%)}to{transform:none}}
  [dir=rtl] .cpmodal-card{animation-name:cpsheet}
  .cpmodal.closing .cpmodal-card,
  [dir=rtl] .cpmodal.closing .cpmodal-card{animation-name:cpsheetout}
  @keyframes cpsheetout{to{transform:translateY(100%)}}
}
@media(prefers-reduced-motion:reduce){.cpmodal-card{animation:none}}

/* The ones they already hold, on the account page. */
.cplist{display:grid;gap:9px}
.cpcard{display:flex;align-items:center;gap:12px;border:1px solid var(--line);border-radius:12px;
  padding:12px 14px;background:#fff}
.cpcard .cpl{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.cpcard .cpl b{font-size:15px;letter-spacing:.06em;font-variant-numeric:tabular-nums}
.cpcard .cpl span{font-size:12.5px;color:var(--mut)}
.cpcard .cpr{display:flex;align-items:center;gap:10px;flex:0 0 auto}
.cpcard .cpr small{font-size:11.5px;color:var(--mut)}
.cpcard.spent{opacity:.55;background:var(--tint)}
.cpcard.spent .cpl b{text-decoration:line-through}

/* ---- the subscribe box, asking to be noticed ----
   The gradient IS the border, painted straight into the border box, so there
   is nothing to clip and nothing to leak: the first attempt rotated a huge
   pseudo-element under `overflow:hidden`, and browsers do not reliably clip a
   composited, animated child to a rounded corner — which is why bars of green
   escaped above and below the box.
   The angle is a registered property so it can be animated. Where @property is
   not supported the declaration below still gives --gfang a value, so the
   border renders as a static gradient rather than disappearing. */
@property --gfang{syntax:'<angle>';inherits:true;initial-value:0deg}

.repeatbox{
  --gfang:0deg;
  position:relative;isolation:isolate;
  border:3px solid transparent;border-radius:13px;padding:13px;
  /* Room above for the glow to sit in. Hard against the last basket line it
     reads as part of the list rather than as its own offer. */
  margin-block:24px 10px;
  background:
    linear-gradient(#fff,#fff) padding-box,
    conic-gradient(from var(--gfang,0deg),
      var(--dark) 0deg, var(--lime) 90deg, #6FD08A 170deg,
      var(--dark) 250deg, var(--lime) 330deg, var(--dark) 360deg) border-box;
  animation:gfspin 4.2s linear infinite}

/* The glow: the same ring again, blurred, sitting just outside.
   A negative z-index child paints ABOVE its parent's background, not below it,
   which is why the blur was washing the inside of the box green. So the white
   is laid back over it by ::after — same z-index, painted later, and only as
   far as the padding box, which leaves the gradient border untouched. */
.repeatbox::before{
  content:'';position:absolute;z-index:-1;inset:-3px;border-radius:16px;
  background:conic-gradient(from var(--gfang,0deg),
      var(--dark) 0deg, var(--lime) 90deg, #6FD08A 170deg,
      var(--dark) 250deg, var(--lime) 330deg, var(--dark) 360deg);
  filter:blur(9px);opacity:.5}
.repeatbox::after{
  content:'';position:absolute;z-index:-1;inset:0;border-radius:10px;background:#fff}

@keyframes gfspin{to{--gfang:360deg}}

/* The same ring, one line high, for a guest who has not signed in yet.
   It borrows .repeatbox's gradient wholesale rather than approximating it —
   two glows that nearly match look like a bug, and this one sits a few
   centimetres above the real thing. */
.subhint{
  --gfang:0deg;
  position:relative;isolation:isolate;display:flex;align-items:center;gap:9px;
  border:2px solid transparent;border-radius:11px;padding:9px 11px;
  margin-block:18px 10px;font-size:12.5px;line-height:1.45;
  background:
    linear-gradient(#fff,#fff) padding-box,
    conic-gradient(from var(--gfang,0deg),
      var(--dark) 0deg, var(--lime) 90deg, #6FD08A 170deg,
      var(--dark) 250deg, var(--lime) 330deg, var(--dark) 360deg) border-box;
  animation:gfspin 4.2s linear infinite}
.subhint::before{
  content:'';position:absolute;z-index:-1;inset:-2px;border-radius:13px;
  background:conic-gradient(from var(--gfang,0deg),
      var(--dark) 0deg, var(--lime) 90deg, #6FD08A 170deg,
      var(--dark) 250deg, var(--lime) 330deg, var(--dark) 360deg);
  filter:blur(7px);opacity:.45}
.subhint::after{
  content:'';position:absolute;z-index:-1;inset:0;border-radius:9px;background:#fff}
/* It is a button now, so it has to stop looking like one of the browser's. */
.subhint{inline-size:100%;text-align:start;cursor:pointer;font:inherit;color:inherit;
  font-size:12.5px;-webkit-tap-highlight-color:transparent}
.subhint:hover::before{opacity:.65}
.subhint:focus-visible{outline:2px solid var(--dark);outline-offset:3px}
.subhint > svg{inline-size:17px;block-size:17px;color:var(--dark);flex:0 0 auto}
.subhint span{min-inline-size:0}
.subhint b{display:block;color:var(--dark);font-size:13px}
.subhint .newtag{margin-inline-start:auto;flex:0 0 auto}
@media(prefers-reduced-motion:reduce){
  .subhint{animation:none}
  .subhint::before{opacity:.38}
}

/* Ticked, it means it: faster, and the glow comes up. */
.repeatbox:has(input:checked){animation-duration:2.4s}
.repeatbox:has(input:checked)::before{opacity:.8;filter:blur(11px)}

@media(prefers-reduced-motion:reduce){
  .repeatbox{animation:none}
  .repeatbox::before{filter:blur(9px);opacity:.42}
}

/* While a coupon is being applied: still readable, obviously not final. */
.sumtotals.busy{opacity:.55;pointer-events:none;transition:opacity .12s}


/* ---- switched off, not removed ----
   A subscription suspends the money-off controls; collection suspends the
   subscribe box. Faded and inert either way, so nobody wonders where the
   thing went, and a note beside it says why. */
.offpickup{opacity:.45;pointer-events:none;filter:grayscale(.4)}
.repeatbox.offpickup{animation:none}
.repeatbox.offpickup::before{opacity:.12;filter:blur(6px)}
.subonly{display:flex;gap:7px;align-items:flex-start;margin:22px 0 -14px;
  font-size:11.5px;color:var(--mut);line-height:1.45}
.subonly .ico{inline-size:14px;block-size:14px;flex:0 0 auto;color:var(--warn);margin-block-start:1px}
.pickupnote{display:flex;gap:7px;align-items:flex-start;margin:2px 0 10px;
  font-size:11.5px;color:var(--mut);line-height:1.45}
.pickupnote .ico{inline-size:14px;block-size:14px;flex:0 0 auto;color:var(--warn);margin-block-start:1px}

/* ---- availability toggle, beside the sort ----
   A three-way choice, not a tick: "only the empty ones" is a real question
   when you are deciding what to restock. */
.listhead{flex-wrap:wrap;gap:12px}
.availtog{display:inline-flex;border:1.5px solid var(--line);border-radius:99px;padding:3px;
  background:#fff;gap:2px;flex:0 0 auto}
.availtog a{padding:7px 14px;border-radius:99px;font-size:13px;font-weight:600;color:var(--mut);
  white-space:nowrap;transition:.14s}
.availtog a:hover{color:var(--dark)}
.availtog a.on{background:var(--dark);color:#fff}
@media(max-width:559px){
  .availtog{inline-size:100%;justify-content:space-between}
  .availtog a{flex:1;text-align:center;padding-inline:8px}
}

/* ======================================= sign in, from inside the checkout ==
   The same slot the subscribe box uses: a guest has nothing to repeat yet, and
   the thing worth asking of them is an account. Two offers beside the Pay
   button would compete with each other and with the button. */
/* Full bleed inside the summary card.
 *
 * .sum pads 18px, so the box cancels that on both sides and pads itself back:
 * a rounded card floating inside another rounded card reads as a second
 * component when it is really a band of this one. Hairlines top and bottom
 * rather than a border all the way round. */
.joinbox{margin-inline:-18px;margin-block:16px;padding:16px 18px;
  border:0;border-block:1px solid var(--line);border-radius:0;
  background:linear-gradient(180deg,#F7FBF8,#fff)}
.join-h{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.join-h > b{font-size:14.5px;flex:1;min-width:0}
.join-pts{background:var(--lime);color:var(--lime-ink,#14241C);border-radius:99px;
  padding:4px 11px;font-size:11.5px;font-weight:700;white-space:nowrap}
.join-sub{margin:6px 0 11px;font-size:11.5px;color:var(--mut);line-height:1.5}

/* Plain radios in a row. Two pills that look like buttons invite a tap and
   then do not go anywhere — the choice is which field to fill in, not an
   action. */
.join-ways{display:flex;gap:18px;margin-block-end:11px}
.join-ways label{display:inline-flex;align-items:center;gap:7px;cursor:pointer;
  font-size:13px;font-weight:600;color:var(--mut)}
.join-ways label:has(input:checked){color:var(--dark)}
.join-ways input{accent-color:var(--dark);inline-size:16px;block-size:16px;margin:0}

/* Three things on one line, and the middle one gives way.
   Choosing SMS inserts the +965 prefix, which is ~46px the row did not have
   before — on a narrow phone that pushed "Send code" past the edge and let the
   whole document scroll sideways. Two defences, because the first one alone
   was evidently not enough on iOS: the field is told in physical units that it
   may shrink to nothing (min-inline-size is the logical spelling and is not
   always honoured on a replaced element), and the row may wrap, so the worst
   case is the button on its own line rather than a page that slides. */
.join-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}
.join-cc{font-size:13px;font-weight:700;color:var(--mut);flex:0 0 auto}
.join-row input{flex:1 1 140px;min-width:0;width:0;min-inline-size:0;
  block-size:42px;border:1.5px solid var(--line);
  border-radius:10px;padding-inline:12px;font:inherit;font-size:14.5px;background:#fff}
.join-row input:focus{border-color:var(--green);outline:none}
.join-row .btn{flex:0 0 auto;block-size:42px;white-space:nowrap}
.join-code{letter-spacing:.45em;font-variant-numeric:tabular-nums;text-align:center;font-weight:700}
.join-sent{margin:0 0 9px;font-size:12px;color:var(--dark);font-weight:600}
.join-alt{display:flex;gap:14px;margin:9px 0 0}
.join-alt .linkish{background:none;border:0;padding:0;font:inherit;font-size:12px;
  color:var(--green);text-decoration:underline;cursor:pointer}
.join-err{margin:9px 0 0;font-size:12px;color:var(--danger);font-weight:600}

/* ---- a line the shop cannot fill ----
   Being told an item is sold out and left to work out the rest is the moment
   a basket gets abandoned. Two words, right under the warning. */
.pfix{display:flex;gap:10px;margin-block-start:4px}
.pfix button{background:none;border:0;padding:0;font:inherit;font-size:11.5px;font-weight:700;
  color:var(--green);text-decoration:underline;cursor:pointer}
.pfix button:hover{color:var(--dark)}
.pfix button[data-fix-drop]{color:var(--mut)}
.pfix button[data-fix-drop]:hover{color:var(--danger)}

/* ---- choosing the replacement ---- */
.swapmodal{position:fixed;inset:0;z-index:140;display:grid;place-items:center;padding:18px}
.swapmodal-scrim{position:absolute;inset:0;background:rgba(10,30,20,.45)}
.swapmodal-card{position:relative;background:#fff;border-radius:16px;
  inline-size:min(520px,100%);max-block-size:min(84vh,680px);display:flex;flex-direction:column;
  box-shadow:0 24px 60px rgba(10,40,25,.28);animation:swapin .2s cubic-bezier(.22,.61,.36,1)}
@keyframes swapin{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}
@media(prefers-reduced-motion:reduce){.swapmodal-card{animation:none}}
.swapmodal-head{display:flex;align-items:flex-start;gap:12px;padding:16px 18px 12px;
  border-block-end:1px solid var(--line)}
.swapmodal-head h3{font-size:16px;margin:0}
.swapmodal-head p{margin:3px 0 0;font-size:12.5px;color:var(--mut)}
.swapmodal-head > div{flex:1;min-width:0}
.swapmodal-x{inline-size:30px;block-size:30px;border-radius:var(--pill);display:grid;place-items:center;
  background:var(--tint);color:var(--mut);flex:0 0 auto}
.swapmodal-x:hover{background:#E7EFE9;color:var(--dark)}
.swapmodal-x .ico{inline-size:14px;block-size:14px}
.swapmodal-body{flex:1;overflow:auto;padding:10px 12px 16px;display:grid;gap:6px;align-content:start}
.swapmodal-none{margin:0;padding:22px 18px;text-align:center;color:var(--mut);font-size:13.5px}

.swapitem{display:grid;grid-template-columns:auto minmax(0,1fr) auto;gap:12px;align-items:center;
  width:100%;text-align:start;background:none;border:1px solid transparent;border-radius:12px;
  padding:9px 10px;cursor:pointer;font:inherit;transition:.14s}
.swapitem:hover{border-color:var(--line);background:var(--tint)}
.si-img{inline-size:46px;block-size:46px;border-radius:9px;overflow:hidden;background:#F6F8F6;flex:0 0 auto}
.si-img img{inline-size:100%;block-size:100%;object-fit:contain}
.si-t{display:block;min-width:0}
.si-t b{display:block;font-size:13.5px;line-height:1.3;overflow-wrap:anywhere}
.si-t small{display:block;font-size:11px;color:var(--mut);margin-block-start:2px}
.si-p{font-size:13px;font-weight:700;white-space:nowrap}

/* A branch that only collects says so once, where the choice would have been. */
.onlypick{display:flex;gap:9px;align-items:flex-start;background:var(--tint);
  border:1px solid var(--line);border-radius:12px;padding:12px 14px;margin:0;
  font-size:13px;color:var(--ink);line-height:1.5}
.onlypick .ico{inline-size:17px;block-size:17px;color:var(--green);flex:0 0 auto;margin-block-start:1px}

/* ---- "this will empty your basket" ----
   Its own classes, not the subscription dialog's: the confirm button is a
   setbranch link like the one that opened this, and `.switchbox` is what lets
   the click handler tell them apart. */
.switchbox{position:fixed;inset:0;z-index:150;display:grid;place-items:center;padding:18px}
.switchbox-scrim{position:absolute;inset:0;background:rgba(10,30,20,.5)}
.switchbox-card{position:relative;background:#fff;border-radius:16px;padding:20px;
  inline-size:min(420px,100%);box-shadow:0 24px 60px rgba(10,40,25,.3);
  animation:submodin .2s cubic-bezier(.22,.61,.36,1)}
.switchbox-card h3{font-size:17px;margin:0 0 6px}
.switchbox-card p{margin:0 0 18px;font-size:13.5px;color:var(--mut);line-height:1.55}
.switchbox-do{display:flex;gap:10px;flex-wrap:wrap}
.switchbox-do .btn{flex:1 1 auto;justify-content:center;text-align:center}
@media(prefers-reduced-motion:reduce){.switchbox-card{animation:none}}

/* ---- three abreast on a wide screen ----
   The substitution choices are three short, mutually exclusive answers to one
   question. Stacked they read as a list of things to do; side by side they read
   as the choice they are. Below 900px they stack, because "Refund the item, do
   not substitute" needs the width. */
.choices.three{grid-template-columns:1fr}
@media(min-width:900px){ .choices.three{grid-template-columns:repeat(3,1fr)} }
.choices.three .choice{justify-content:center}
/* ...unless one of them wraps. Three columns are only worth having while all
   three labels still read as single lines; a wrapped label beside two short
   ones is a ragged row, so the script below drops the lot back to a stack. */
.choices.three.nofit{grid-template-columns:1fr}

/* ---- iPhone: tapping + twice is a double tap ----
   Safari waits ~300ms after a tap to see whether a second one is coming, and
   treats the pair as zoom. On a stepper that is exactly what adding two of
   something looks like, so the page zoomed instead of counting. Telling the
   browser these elements only ever want ordinary gestures removes both the
   zoom and the delay. */
.stepper button,.pstep button,.ba-step button,.btn,.pay,.choice,.daychip,.slotpill,
.cx,.swapmodal button,.qbtn,label.pay,[data-add],[data-inc],[data-dec]{touch-action:manipulation}

/* ---- nothing scrolls the page sideways ----
   The pieces that are meant to scroll across (the category bar, the coupon
   tray, the day strip) each own their scroll container; the document itself
   never should. `clip` rather than `hidden` on purpose — `hidden` would make
   the root a scroll container and break every `position:sticky` on the page.
   Safari below 16 ignores it, which is no worse than today. */
html{overflow-x:clip}

/* ---- putting money on account ----
   One amount, one button. The presets are a convenience, not the only choice,
   so they sit above the field rather than replacing it. */
.topup{background:#fff;border:1px solid var(--line);border-radius:var(--r);
  padding:16px;margin-block:16px}
.topup-h{display:flex;flex-direction:column;gap:3px;margin-block-end:12px}
.topup-h b{font-size:15px}
.topup-h small{font-size:12.5px;color:var(--mut);line-height:1.45}
.topup-pre{display:flex;gap:8px;flex-wrap:wrap;margin-block-end:10px}
.topup-chip{border:1.5px solid var(--line);background:#fff;border-radius:var(--pill);
  padding:7px 14px;font-size:13px;font-weight:600;cursor:pointer;touch-action:manipulation}
.topup-chip:hover{border-color:var(--green);color:var(--green)}
.topup-chip.on{border-color:var(--dark);background:#F1F6F2;color:var(--dark)}
.topup-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}
.topup-cur{font-size:13px;font-weight:700;color:var(--mut);flex:0 0 auto}
.topup-row input{flex:1 1 140px;min-width:0;width:0;block-size:42px;border:1.5px solid var(--line);
  border-radius:10px;padding-inline:12px;font:inherit;font-size:15px;font-weight:600;
  background:#fff;font-variant-numeric:tabular-nums}
.topup-row input:focus{border-color:var(--green);outline:none}
.topup-row .btn{flex:0 0 auto;block-size:42px;white-space:nowrap}
.topup-note{margin:10px 0 0;font-size:11.5px;color:var(--mut);line-height:1.45}

/* ========================================================= PROFILE ========
   The account page leads with the person, then what they are worth, then the
   things they can act on. Each section is a card so the page reads as a stack
   of answers rather than one long column of headings. */
.prof{display:flex;align-items:flex-start;justify-content:space-between;gap:18px;
  flex-wrap:wrap;background:linear-gradient(135deg,#F3F8F4,#FFF 62%);
  border:1px solid var(--line);border-radius:var(--r);padding:20px;margin-block:6px 16px}
.prof-id{display:flex;gap:16px;align-items:center;min-width:0}
.prof-av{inline-size:62px;block-size:62px;border-radius:50%;flex:0 0 auto;display:grid;
  place-items:center;background:var(--dark);color:var(--lime);
  font-size:23px;font-weight:800;letter-spacing:.02em}
.prof-who{min-width:0}
.prof-who h1{font-size:26px;margin:0 0 3px;letter-spacing:-.03em}
.prof-who p{margin:0;font-size:13px;color:var(--mut);overflow-wrap:anywhere}
.prof-since{display:flex;align-items:center;gap:6px;margin-block-start:6px!important;
  font-size:12px;color:var(--green)!important;font-weight:600}
.prof-since .ico{inline-size:14px;block-size:14px}

.prof-stats{display:grid;gap:12px;margin-block-end:26px;
  grid-template-columns:repeat(auto-fit,minmax(170px,1fr))}
.pstat{border:1px solid var(--line);background:#fff;border-radius:var(--r);
  padding:16px;display:flex;flex-direction:column;gap:3px}
.pstat span{font-size:11px;text-transform:uppercase;letter-spacing:.07em;color:var(--mut);font-weight:700}
.pstat b{font-size:27px;font-weight:700;letter-spacing:-.03em;font-variant-numeric:tabular-nums;line-height:1.15}
.pstat small{font-size:11.5px;color:var(--mut);line-height:1.45}
.pstat .btn{align-self:flex-start;margin-block-start:9px}
.pstat-money{background:var(--dark);border-color:var(--dark);color:#fff}
.pstat-money span{color:rgba(255,255,255,.72)}
.pstat-money small{color:rgba(255,255,255,.72)}

/* The account page's own card. NOT .pcard — that is the shop's product card,
   and naming this one the same quietly restyled all 179 of them. */
.acard{background:#fff;border:1px solid var(--line);border-radius:var(--r);
  padding:18px;margin-block-end:20px}
.acard-h{display:flex;align-items:center;gap:9px;font-size:15px;margin:0 0 14px}
.acard-h .ico{inline-size:18px;block-size:18px;color:var(--green);flex:0 0 auto}
/* ---- wallet / points, as two tabs ----
   Radio buttons and labels, so the switch costs no JavaScript. The inputs are
   moved off-screen rather than display:none — a hidden input cannot be focused,
   and these are the only way to reach the second tab by keyboard. */
.atabs{padding:0;overflow:hidden}
.atabs > input{position:absolute;opacity:0;pointer-events:none;inline-size:1px;block-size:1px}
.atabs-h{display:flex;border-block-end:1px solid var(--line)}
.atabs-h label{flex:1 1 0;min-inline-size:0;display:flex;align-items:center;gap:8px;
  padding:13px 16px;cursor:pointer;font-size:13.5px;font-weight:700;color:var(--mut);
  border-block-end:2px solid transparent;margin-block-end:-1px;transition:.14s;
  -webkit-tap-highlight-color:transparent}
.atabs-h label span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.atabs-h label b{margin-inline-start:auto;font-variant-numeric:tabular-nums;
  white-space:nowrap;color:var(--ink)}
.atabs-h label .ico{inline-size:17px;block-size:17px;flex:0 0 auto}
.atabs-h label:hover{color:var(--ink);background:#f7faf8}
.atab{display:none;padding:4px 18px 16px}
/* The pane whose radio is checked. Both inputs sit before both panes, so a
   plain sibling combinator reaches them. */
#tab-wallet:checked ~ .atab-wallet,
#tab-points:checked ~ .atab-points{display:block}
#tab-wallet:checked ~ .atabs-h label[for=tab-wallet],
#tab-points:checked ~ .atabs-h label[for=tab-points]{color:var(--green);
  border-block-end-color:var(--green);background:#fff}
/* Keyboard focus has to be visible on the LABEL, since the input is off-screen. */
.atabs > input:focus-visible + input + .atabs-h label[for=tab-wallet],
.atabs > input:focus-visible ~ .atabs-h label[for=tab-points]{outline:2px solid var(--green);
  outline-offset:-2px}
/* No CSS at all: both lists simply show, which is a page rather than a fault. */
@supports not (selector(:checked ~ *)){ .atab{display:block} }
.acard .ordrow:last-child,.acard .wrow:last-child{border-block-end:0;padding-block-end:0}
.pempty{margin:0;font-size:13px;color:var(--mut);line-height:1.55}

/* A status that reads at a glance: finished is quiet green, cancelled is grey,
   everything in between is simply in progress. */
.o-status{font-size:11.5px;font-weight:700;padding:3px 10px;border-radius:var(--pill);
  background:#EEF4F0;color:var(--green)}
.o-status.done{background:#E7F6ED;color:#12713C}
.o-status.off{background:#F2F3F2;color:var(--mut)}

/* The top-up box belongs to the profile stack, so it matches the cards. */
.topup{margin-block:0 20px}

/* ---- a guest proving their number at the last step ---- */
.otpgate{position:fixed;inset:0;z-index:160;display:grid;place-items:center;padding:18px}
.otpgate-scrim{position:absolute;inset:0;background:rgba(10,30,20,.5)}
.otpgate-card{position:relative;background:#fff;border-radius:16px;padding:22px;
  inline-size:min(420px,100%);box-shadow:0 24px 60px rgba(10,40,25,.3);
  animation:submodin .2s cubic-bezier(.22,.61,.36,1)}
.otpgate-card h3{margin:0 0 6px;font-size:17px}
.otpgate-sub{margin:0 0 12px;font-size:13px;color:var(--mut);line-height:1.55}
.otpgate-num{margin:0 0 12px;font-size:13px;font-weight:600;color:var(--green)}
.otpgate-row{margin-block-end:10px}
.otpgate-row input{inline-size:100%;block-size:48px;border:1.5px solid var(--line);
  border-radius:10px;padding-inline:14px;font:inherit;font-size:19px;background:#fff}
.otpgate-row input:focus{border-color:var(--green);outline:none}
.otpgate-err{margin:0 0 10px;font-size:12.5px;color:var(--danger);font-weight:600}
.otpgate-do{display:flex;gap:10px;flex-wrap:wrap}
.otpgate-do .btn{flex:1 1 auto;justify-content:center;text-align:center}
.otpgate-alt{margin:12px 0 0;text-align:center;font-size:12.5px}
@media(prefers-reduced-motion:reduce){.otpgate-card{animation:none}}

/* ---- a number that has been proved ----
   A tick in a green disc, no label. It sits beside a phone number that is
   already the widest thing on the line, and "Verified" is a state nobody acts
   on — the colour and the mark carry it. */
.verified{display:inline-grid;place-items:center;margin-inline-start:7px;
  inline-size:17px;block-size:17px;border-radius:50%;
  background:#E7F6ED;color:#12713C;vertical-align:-3px}
.verified .ico{inline-size:11px;block-size:11px;stroke-width:3}

/* ---- iOS zooms into any field smaller than 16px ----
   Safari decides a sub-16px control is too small to read and zooms the page on
   focus, which then leaves the layout scrolled sideways. The fix is the font
   size itself — `maximum-scale=1` would do it too, but by taking pinch-zoom
   away from everybody, which is a real accessibility loss for a cosmetic
   problem. 16px only on touch screens; the desktop keeps its smaller type. */
@media(max-width:899px){
  input:not([type=checkbox]):not([type=radio]):not([type=range]),
  select,textarea{font-size:16px!important}
  .join-code,.otpgate-row input{font-size:19px!important;letter-spacing:.3em}
}
.o-status.wait{background:#FFF4E0;color:#8A6400}

/* ---- the delivery minimum, as a pill ----
   Same shape as the checkout pill, amber instead of green. It floats rather
   than scrolling away at the top, so it is still on screen when they are three
   fields down and reaching for the button. A warning, not an error: nothing
   has gone wrong yet, and there are two ways out — add more, or collect. */
.minpill{position:fixed;inset-block-end:28px;inset-inline:0;z-index:72;
  margin-inline:auto;inline-size:fit-content;max-inline-size:calc(100% - 32px);
  display:flex;align-items:center;gap:11px;
  padding:11px 18px;border-radius:99px;
  background:#B8860B;color:#fff;font-weight:500;font-size:14px;
  box-shadow:0 10px 30px rgba(120,80,10,.32);
  animation:pillin .26s cubic-bezier(.22,.61,.36,1)}
.minpill:hover{transform:translateY(-1px)}
.mp-i{display:grid;place-items:center;flex:0 0 auto}
.mp-i .ico{inline-size:17px;block-size:17px}
.mp-t{min-inline-size:0}          /* allowed to wrap: a cropped warning is no warning */
.mp-go{flex:0 0 auto;background:rgba(255,255,255,.22);border-radius:99px;
  padding:3px 11px;font-size:12.5px;font-weight:800}

/* Re-triggerable: the class is removed and re-added on every nudge. */
.minpill.nudge{animation:minshake .42s cubic-bezier(.36,.07,.19,.97)}
@keyframes minshake{
  10%,90%{transform:translateX(-2px)}
  20%,80%{transform:translateX(4px)}
  30%,50%,70%{transform:translateX(-7px)}
  40%,60%{transform:translateX(7px)}
}
@media(max-width:640px){
  .minpill{font-size:13px;padding:10px 14px;gap:8px}
}
/* A phone already has the buy bar down there; lift the pill clear of it. */
body:has(.buybar:not([hidden])) .minpill{inset-block-end:90px}
@media(prefers-reduced-motion:reduce){
  .minpill{animation:none}
  .minpill.nudge{animation:none;outline:3px solid #FFE9B0;outline-offset:2px}
}


/* ---- last line of defence against a sideways page ----
   Every top-level band is told it may not exceed the viewport. Anything that
   genuinely needs to be wider (the category strip, the coupon tray, a table)
   carries its own overflow-x and is unaffected.

   `.main` is in the clip list but NOT in the max-inline-size list, and that is
   the whole point of splitting this rule in two.

   max-inline-size IS max-width — the logical form of the same property. Listed
   here, last in the file and at the same specificity as `.wrap`, it quietly
   beat `.wrap{max-width:var(--wrap)}` and every page ran edge to edge. It was
   invisible for weeks because the pages anyone looked at were `.main.wide`
   (two classes, so it won) and the rest were assumed to be capped. `.main` is
   a block element: it was never going to exceed its container anyway, so the
   declaration bought nothing and cost the page's column. */
.tinybar,.topwrap,.catbar,.site-foot{max-inline-size:100%}
.tinybar,.topwrap,.catbar,.main,.site-foot{overflow-x:clip}


/* ---------------------------------------------- basket: empty it in one go */
.pane-clear{margin-inline-start:auto;margin-inline-end:6px;border:0;background:none;
  font:inherit;font-size:12px;font-weight:600;color:var(--mut);cursor:pointer;
  padding:5px 8px;border-radius:8px;white-space:nowrap}
.pane-clear:hover{background:#FDECEC;color:#b3261e}
.pane-clear:focus-visible{outline:2px solid var(--green);outline-offset:1px}
.pane-clear[data-armed]{background:#FDECEC;color:#b3261e}


/* --------------------------------------------- listing tools: a single row
   Filters, sort and the in-stock switch sit on one line at every width, all
   the same height so the row reads as one control strip rather than three
   borrowed ones. --tool-h is that height, in one place. */
:root{--tool-h:44px}
.listtools{display:flex;align-items:center;gap:10px;flex-wrap:nowrap}
.listtools>*{align-self:center}
.listtools .fbtn,
.listtools .sorter select,
.listtools .swtog{block-size:var(--tool-h);min-block-size:var(--tool-h);
  border-radius:99px;box-sizing:border-box;line-height:1;
  display:inline-flex;align-items:center;margin:0}
.listtools .sorter{align-items:center;margin:0}
.listtools .fbtn{padding-inline:16px;color:var(--ink);-webkit-text-fill-color:var(--ink)}
.listtools .fbtn .ico{color:var(--mut)}
.listtools .sorter{display:flex}

/* The native arrow was being clipped by the pill's own padding, which is what
   cut "Recommended" short. Draw it instead, and reserve room for it. */
.listtools .sorter select{
  -webkit-appearance:none;appearance:none;
  padding-inline:16px 38px;font-weight:600;
  color:var(--ink);-webkit-text-fill-color:var(--ink);
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%2314241C' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-size:12px 8px;
  background-position:right 15px center}
[dir=rtl] .listtools .sorter select{background-position:left 15px center}

.swtog{display:inline-flex;align-items:center;gap:10px;flex:0 0 auto;
  padding-inline:16px;border:1.5px solid var(--line);background:#fff;
  color:var(--ink);font-weight:600;font-size:13.5px;text-decoration:none;white-space:nowrap}
.swtog:hover{border-color:#CFE0D6;background:var(--tint)}
.swtog i{position:relative;inline-size:38px;block-size:22px;border-radius:99px;
  background:#C3CBD1;flex:0 0 auto;transition:background .18s}
.swtog i::after{content:"";position:absolute;inset-block-start:3px;inset-inline-start:3px;
  inline-size:16px;block-size:16px;border-radius:50%;background:#fff;
  box-shadow:0 1px 2px rgba(0,0,0,.25);transition:translate .18s}
.swtog.on{border-color:var(--dark)}
.swtog.on i{background:var(--dark)}
.swtog.on i::after{translate:16px 0}
[dir=rtl] .swtog.on i::after{translate:-16px 0}

@media(max-width:899px){
  :root{--tool-h:42px}
  .listhead{align-items:stretch}
  .listtools{inline-size:100%}
  .listtools .fbtn{flex:0 1 auto;justify-content:center;padding-inline:14px}
  .listtools .sorter{flex:1 1 0;min-inline-size:0}
  .listtools .sorter select{inline-size:100%}
  .swtog{padding-inline:12px;gap:8px;font-size:13px}
  /* the funnel is understood on its own; the word is what pushes the row wide */
  .listtools .fbtn{inline-size:var(--tool-h);padding-inline:0;justify-content:center}
  .listtools .fbtn-t{display:none}
  .listtools .fbtn .fcount{position:absolute;inset-block-start:-4px;inset-inline-end:-4px}
  .listtools .fbtn{position:relative}
}


/* ----------------------------------------------------- homepage additions */
.row-h h2 .rowsub{display:block;font-size:12px;font-weight:500;color:var(--mut);margin-block-start:2px}
.aisletiles{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:10px}
.aisletile{display:flex;align-items:center;justify-content:center;text-align:center;
  min-block-size:72px;padding:14px 12px;border:1.5px solid var(--line);border-radius:14px;
  background:#fff;font-weight:650;color:var(--ink);text-decoration:none;
  transition:border-color .15s,background .15s,transform .15s}
.aisletile:hover{border-color:#CFE0D6;background:var(--tint);transform:translateY(-1px)}
@media(max-width:600px){
  .aisletiles{grid-template-columns:repeat(2,1fr);gap:8px}
  .aisletile{min-block-size:62px;font-size:14px}
}


/* ------------------------------------------- basket pane: one action row */
.pane-go{display:flex;align-items:stretch;gap:10px}
.pane-basket{flex:0 0 auto;display:grid;place-items:center;padding:12px 16px;
  border:1.5px solid var(--line);border-radius:99px;background:#fff;color:var(--ink);
  font-weight:650;font-size:14px;white-space:nowrap;text-decoration:none}
.pane-basket:hover{border-color:#CFE0D6;background:var(--tint)}
.pane-check{flex:1 1 auto;display:flex;align-items:center;justify-content:center;gap:10px;
  padding:12px 18px;border-radius:99px;background:var(--lime);color:var(--lime-ink,#14241C);
  font-weight:700;font-size:14.5px;white-space:nowrap;text-decoration:none}
.pane-check:hover{filter:brightness(.96)}
.pane-check .gc-n{background:var(--dark);color:#fff}
.pane-check .gc-v{opacity:.72}
@media(max-width:380px){
  .pane-basket{padding-inline:12px;font-size:13px}
  .pane-check{padding-inline:14px;font-size:13.5px;gap:8px}
}
