/** Shopify CDN: Minification failed

Line 4022:67 Unexpected bad string token
Line 4022:109 Unterminated string token

**/
/* ============================================================
   Cold outside, warm where the fruit is.
   Everything on this page is cold jade except the decision
   panel and the gold — because the fruit is the only warm
   thing in a −40°C supply chain.
   ============================================================ */
:root{
  --abyss:#0E4230;
  --jade:#155239;
  --deep:#0A3325;
  --cream:#F6F2E4;
  --ice:#EAF4EE;
  --mist:#ADC8B8;
  --gold:#F5C136;
  --gold-soft:#FFDC80;
  /* The wordmark only. Brighter and greener-free than --gold so "GOLD"
     reads as yellow rather than amber against the dark green. */
  --mark-yellow:#FFD11F;
  --flesh:#FDF5E4;
  --flesh-2:#F7E7C2;
  --ink:#12291D;
  --ink-2:#4C6152;
  --glass:rgba(255,255,255,.06);
  --glass-line:rgba(232,242,236,.14);

  --dsp:'Bricolage Grotesque',system-ui,sans-serif;
  --ui:'Plus Jakarta Sans',system-ui,-apple-system,sans-serif;
  --mark:'Montserrat','Plus Jakarta Sans',system-ui,sans-serif;
  --cjk:'Noto Sans SC','Noto Sans TC',sans-serif;

  --r-panel:30px;
  --r-card:20px;
  --r-pill:999px;
}
html[lang="zh-Hant"]{--cjk:'Noto Sans TC','Noto Sans SC',sans-serif}
*,*::before,*::after{box-sizing:border-box}
html{
  -webkit-text-size-adjust:100%;
  background:#0E4230;
  color-scheme:dark;
  min-height:100%;
}
body{
  margin:0;background:#0E4230;color:var(--ice);min-height:100vh;
  font-family:var(--ui);font-size:1.0625rem;line-height:1.55;font-weight:500;
  -webkit-font-smoothing:antialiased;font-variant-numeric:tabular-nums;
}
html[lang="zh-Hans"] body,html[lang="zh-Hant"] body{font-family:var(--cjk),var(--ui)}
.page-bg{position:fixed;inset:0;background:#0E4230;z-index:0;pointer-events:none}
.page{
  position:relative;z-index:1;background:#0E4230;
  max-width:480px;margin:0 auto;min-height:100vh;
  /* No bottom padding here. It used to reserve 116px for the fixed dock, but
     .page is the page green and the footer beneath it is darker — so the
     reserve rendered as an empty lighter block below the footer that you could
     scroll into. The space is still needed; it just belongs to the footer, so
     it reads as part of it. See .foot below. */
  /* overflow-x:clip was removed: a clipping ancestor takes position:sticky off
     the compositor in several engines, which is felt as a header that lags
     behind the scroll. Nothing in the page overflows horizontally at any width
     or in any drawer state — measured — so the clip was insurance being paid
     for on every frame. */
}
.dsp{
  font-family:var(--dsp);
  font-variation-settings:'wdth' 90,'opsz' 60;
  font-weight:800;
}
html[lang="zh-Hans"] .dsp,html[lang="zh-Hant"] .dsp{font-family:var(--cjk);font-weight:700}

/* ---------- header ---------- */
.strip{
  display:flex;align-items:center;justify-content:center;gap:10px;
  background:var(--gold);color:var(--abyss);
  padding:14px 16px;font-size:0.9375rem;font-weight:800;letter-spacing:.01em;
}
.strip .flag{width:26px;height:18px;display:block;flex:0 0 auto;border-radius:2px}
.bar{
  position:sticky;top:0;z-index:50;
  display:flex;align-items:center;justify-content:space-between;gap:10px;
  padding:14px 16px;
  background:rgba(14,66,48,.96);backdrop-filter:blur(14px);
}
.bar-r{display:flex;align-items:center;gap:8px;flex:0 0 auto}
.logo{display:flex;align-items:center;gap:9px;flex:0 0 auto;min-width:0}
.logo svg{width:34px;height:34px;display:block;flex:0 0 auto}
.mark{display:block;line-height:1}
/* The wordmark has its own face. The display font's width/optical axes have
   to be switched off explicitly — they are inherited from --dsp's variable
   settings and would narrow the fallback while Montserrat loads. */
.mark b{
  display:block;white-space:nowrap;font-family:var(--mark);
  font-variation-settings:normal;
  font-weight:800;font-size:1.3125rem;letter-spacing:-.015em;color:var(--ice);
}
.mark i{font-style:normal;color:var(--gold)}
.lang{
  font-family:var(--ui);font-size:0.9375rem;font-weight:700;color:var(--ice);
  background:var(--glass) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='11' height='7'%3E%3Cpath d='M1 1l4.5 4.5L10 1' stroke='%23F5C136' stroke-width='1.7' fill='none' stroke-linecap='round'/%3E%3C/svg%3E") no-repeat right 11px center;
  border:1px solid var(--glass-line);border-radius:var(--r-pill);
  padding:10px 30px 10px 13px;appearance:none;-webkit-appearance:none;
}
.lang option{color:#12291D;background:#FDF5E4}
.lang:focus-visible{outline:2px solid var(--gold);outline-offset:3px}

/* ---------- cart ---------- */
.cartbtn{
  display:flex;align-items:center;gap:8px;cursor:pointer;
  background:var(--glass);border:1px solid var(--glass-line);border-radius:var(--r-pill);
  padding:10px 13px 10px 12px;color:var(--ice);
  font-family:var(--ui);font-size:0.9375rem;font-weight:700;flex:0 0 auto;
}
.cartbtn svg{width:19px;height:19px;display:block}
.cartbtn span{
  min-width:22px;height:22px;border-radius:99px;background:var(--gold);color:var(--abyss);
  display:grid;place-items:center;font-size:0.875rem;font-weight:800;padding:0 7px;
}
.cartbtn:focus-visible{outline:2px solid var(--gold);outline-offset:3px}

.scrim{
  position:fixed;inset:0;z-index:60;background:rgba(4,22,15,.76);backdrop-filter:blur(3px);
  opacity:0;pointer-events:none;
}
.scrim.on{opacity:1;pointer-events:auto}
@media (prefers-reduced-motion:no-preference){.scrim{transition:opacity .28s ease}}

.drawer{
  /* A panel that comes in from the side and owns the full height of the screen,
     at every width. It used to be a bottom sheet on a phone, capped at 94svh
     and sized to its content — which meant the last thing in it, the checkout
     button, was reliably the thing that fell off the bottom and had to be
     scrolled to. A full-height panel has the whole viewport to lay out in, so
     everything the shopper needs to check before paying can be on screen at
     once. That is worth more here than keeping the product peeking out above. */
  position:fixed;top:0;right:0;bottom:0;left:auto;z-index:61;
  width:min(430px,100vw);max-height:none;min-height:0;
  /* svh first as the floor, then dvh where it exists.

     svh alone was leaving a band of the page showing under the panel on a real
     iPhone: svh is the SMALL viewport, the height you get with Safari's address
     bar expanded, and the bar is collapsed by the time anyone opens the cart.
     Measured on a 430x932 phone the panel came up 82px short of the bottom, so
     the page behind it showed through beneath the guarantee line and the whole
     thing read as a sheet that had failed to finish opening.

     dvh is the honest unit here. Its usual objection — that it resizes mid-
     scroll as the browser chrome hides — cannot happen to this panel: opening
     the drawer locks the page behind it, so the chrome is fixed for as long as
     the panel is up. And the height media queries below read the same viewport,
     so the compaction steps follow it rather than fighting it. */
  height:100svh;height:100dvh;
  background:var(--abyss);
  border-top:0;border-left:1px solid var(--glass-line);border-radius:0;
  display:flex;flex-direction:column;transform:translateX(102%);
  box-shadow:-24px 0 60px -20px rgba(0,0,0,.7);
  overflow:hidden;
}
.drawer.on{transform:none}
@media (prefers-reduced-motion:no-preference){
  /* One transition now — the panel travels the same way at every width. */
  .drawer{transition:transform .34s cubic-bezier(.2,.75,.25,1)}
}
.dr-head{
  display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:20px 20px 16px;border-bottom:1px solid var(--glass-line);flex:0 0 auto;
}
.dr-head h2{margin:0;font-size:1.375rem;letter-spacing:-.02em;color:var(--ice)}
.dr-x{
  background:var(--glass);border:1px solid var(--glass-line);color:var(--ice);
  width:38px;height:38px;border-radius:50%;cursor:pointer;font-size:1.25rem;line-height:1;
}
.dr-x:focus-visible{outline:2px solid var(--gold);outline-offset:3px}
.dr-body{flex:1 1 auto;overflow-y:auto;padding:18px 20px 8px;-webkit-overflow-scrolling:touch;
  /* A column, so the gap property below actually applies and so the last row
     can push itself to the bottom. As a block it was neither. */
  display:flex;flex-direction:column}

.line{display:flex;gap:14px;align-items:flex-start}
.line img{width:64px;height:64px;border-radius:12px;object-fit:cover;flex:0 0 auto;background:var(--jade)}
.line-m{flex:1 1 auto;min-width:0}
.line-m b{display:block;font-size:1.0625rem;font-weight:800;color:var(--ice);line-height:1.25}
.line-each{display:block;font-size:0.90625rem;color:var(--mist);margin-top:3px}
/* "Hop 4 trai nguyen - 18-22 lb" runs to a third line in Vietnamese and
   pushes the cart past one screen. Drop a point rather than clamp it: the
   weight is the half of the line a shopper is actually checking. */
html[lang="vi"] .line-each{font-size:0.84375rem}
html[lang="vi"] .drawer .line-m b{font-size:0.96875rem}
.line-p{font-size:1.1875rem;font-weight:800;color:var(--ice);flex:0 0 auto}

.dr-foot{flex:0 0 auto;padding:14px 20px calc(16px + env(safe-area-inset-bottom));border-top:1px solid var(--glass-line)}
.dr-cta{
  display:block;width:100%;border:0;cursor:pointer;background:var(--gold);color:var(--abyss);
  padding:19px 16px;border-radius:var(--r-pill);
  font-family:var(--ui);font-weight:800;font-size:1.125rem;letter-spacing:-.01em;
}
html[lang="zh-Hans"] .dr-cta,html[lang="zh-Hant"] .dr-cta{font-family:var(--cjk)}
@media (prefers-reduced-motion:no-preference){.dr-cta{transition:transform .15s ease}}
.dr-cta:active{transform:scale(.985)}
.dr-cta:focus-visible{outline:3px solid var(--ice);outline-offset:3px}

/* ---------- gallery ---------- */
.shot{
  margin:0 16px;aspect-ratio:1/1;overflow:hidden;border-radius:var(--r-card);
  background:var(--jade);
}
/* The gallery is a snap track now. overflow-x on the track (not the .shot)
   keeps the badge, which is absolutely positioned against .shot, from
   scrolling away with the slides. */
.shot-track{
  display:flex;height:100%;
  overflow-x:auto;overflow-y:hidden;
  scroll-snap-type:x mandatory;
  -webkit-overflow-scrolling:touch;scrollbar-width:none;
  overscroll-behavior-x:contain;
}
/* The animation lives in CSS, not in a scrollTo() call. Measured in-browser:
   scrollTo({behavior:'smooth'}) and scrollIntoView({behavior:'smooth'}) both
   move this snap container by 0px, while assigning scrollLeft moves it exactly
   — so the code assigns, and this makes the assignment animate. Where a
   browser declines to animate, the jump still lands in the right place. */
@media (prefers-reduced-motion:no-preference){
  .shot-track{scroll-behavior:smooth}
}
.shot-track::-webkit-scrollbar{display:none}
.shot-track:focus-visible{outline:2px solid var(--gold);outline-offset:-2px}
.shot-slide{
  flex:0 0 100%;margin:0;height:100%;
  /* scroll-snap-align only. scroll-snap-stop:always stops a fling at every
     slide, which sounds right — but it also refuses a programmatic smooth
     scroll across more than one slide, so tapping thumbnail 5 moved nothing at
     all. Measured: smooth scrollTo landed at 0, instant landed correctly. */
  scroll-snap-align:center;
}
.shot-slide img{width:100%;height:100%;object-fit:cover;display:block}
.thumbs{
  --g:7px;
  display:flex;gap:var(--g);padding:8px 16px 5px;overflow-x:auto;
  scroll-snap-type:x proximity;scroll-padding-inline:16px;
  -webkit-overflow-scrolling:touch;scrollbar-width:none;
}
.thumbs::-webkit-scrollbar{display:none}
.thumbs figure{
  margin:0;flex:0 0 calc((100% - 4 * var(--g)) / 5);aspect-ratio:1/1;
  overflow:hidden;cursor:pointer;position:relative;
  border-radius:12px;background:var(--jade);scroll-snap-align:start;
}
.thumbs figure img{width:100%;height:100%;object-fit:cover;display:block;opacity:.45}
.thumbs figure.on img{opacity:1}
/* The selection ring is drawn INSIDE the thumbnail, not around it.

   Around it, the ring lived outside the figure's box and the strip clipped it:
   overflow-x:auto forces the other axis to clip too, so it was cut off top and
   bottom, and the first and last thumbnails — flush against the scroller's
   edges — lost their side of it as well. Padding the scroller would fix that
   and reintroduce the bug the side gutter is a margin to avoid: a seventh
   thumbnail showing through, past the edge of the photograph above.

   An outline with a negative offset draws over the image, follows the corner
   radius, takes no layout space and cannot leave the box — so there is nothing
   to clip, on any side, and the strip keeps its original measurements. */
.thumbs figure.on{outline:2px solid var(--gold);outline-offset:-2px}
.thumbs figure:focus-visible{outline:2px solid var(--ice);outline-offset:-2px}

/* ---------- masthead ---------- */
.head{padding:22px 20px 0}
.rating{display:flex;align-items:center;flex-wrap:wrap;gap:8px;row-gap:5px;margin:0 0 13px}
.r-dot{width:4px;height:4px;border-radius:50%;background:var(--mist);opacity:.55;flex:0 0 auto}
/* One weight across the whole line, and the heaviest the UI face carries.
   The figure and the words that qualify it are one claim; setting the number
   heavier than its own unit reads as two. */
.r-sold{font-size:0.90625rem;font-weight:800;color:var(--gold);letter-spacing:0}
.stars{position:relative;display:inline-flex;flex:0 0 auto;line-height:1}
.stars .s-bg,.stars .s-fg{display:flex;gap:2px}
.stars .s-fg{position:absolute;top:0;left:0;overflow:hidden;width:0}
.stars svg{width:17px;height:17px;display:block;flex:0 0 auto}
.stars .s-bg svg{fill:rgba(234,244,238,.22)}
.stars .s-fg svg{fill:var(--gold)}
.r-count{font-size:0.90625rem;font-weight:600;color:var(--mist);letter-spacing:0}
h1{margin:0;font-size:clamp(1.75rem,7.7vw,2.5rem);line-height:1.04;letter-spacing:-.042em;color:var(--ice)}
html[lang="zh-Hans"] h1,html[lang="zh-Hant"] h1{font-size:clamp(1.875rem,8.4vw,2.75rem);letter-spacing:.01em}
html[lang="vi"] h1{font-size:clamp(1.5rem,6.4vw,2.0625rem)}
/* The gold half starts its own line. It used to run on inline behind a
   generated space, which left the break to wherever the measure happened to
   fall — "Premium Whole Musang King" then a lonely "Durian". As a block the
   break is the one the name actually has. */
h1 em{display:block;font-style:normal;color:var(--gold)}
.lede{margin:11px 0 0;font-size:1rem;line-height:1.5;color:var(--mist);max-width:34ch}

.spec{
  margin:14px 20px 0;padding:12px 16px;border-radius:var(--r-pill);
  background:var(--glass);border:1px solid var(--glass-line);
  font-size:0.96875rem;font-weight:600;color:var(--ice);text-align:center;letter-spacing:.01em;
}

/* ---------- buy: on the cold ground, gold marks the choice ---------- */
.buy{padding:24px 16px 0}
.buy .ask{
  display:flex;align-items:baseline;justify-content:space-between;gap:12px;
  margin:0 4px 14px;
}
.buy h2{margin:0;font-size:1.6875rem;line-height:1.05;letter-spacing:-.03em;color:var(--ice)}
.buy .hint{margin:0;font-size:0.9375rem;color:var(--mist);text-align:right;flex:0 1 auto}

.tier{
  display:flex;align-items:center;gap:14px;cursor:pointer;position:relative;
  padding:15px 16px;border-radius:var(--r-card);min-height:92px;
  background:var(--jade);border:1.5px solid var(--glass-line);margin-bottom:10px;
}
@media (prefers-reduced-motion:no-preference){
  .tier{transition:border-color .16s ease,background .16s ease,box-shadow .16s ease}
}
.tier.on{
  border-color:var(--gold);background:#175139;
  box-shadow:0 0 0 4px rgba(240,180,41,.13), 0 14px 30px -14px rgba(0,0,0,.7);
}
.tier input{
  appearance:none;-webkit-appearance:none;margin:0;flex:0 0 auto;
  width:25px;height:25px;border-radius:50%;border:2px solid rgba(232,242,236,.34);
  background:transparent;display:grid;place-items:center;
}
.tier input:checked{border-color:var(--gold)}
.tier input:checked::after{content:"";width:13px;height:13px;border-radius:50%;background:var(--gold)}
.tier input:focus-visible{outline:2px solid var(--gold);outline-offset:4px}
.t-l{flex:1 1 auto;min-width:0}
.t-qty{display:block;font-family:var(--dsp);font-variation-settings:'wdth' 88,'opsz' 40;
  font-weight:700;font-size:1.5rem;line-height:1.06;letter-spacing:-.025em;color:var(--ice)}
.tier.on .t-qty{color:var(--gold-soft)}
.t-cn{display:block;font-size:0.90625rem;color:var(--mist);margin-top:3px;line-height:1.3}
.pips{display:flex;gap:3px;margin-top:9px;flex-wrap:wrap;opacity:.5}
.tier.on .pips{opacity:1}
.pips svg{width:24px;height:24px;display:block}
.t-r{flex:0 0 auto;text-align:right}
.t-price{display:block;font-family:var(--dsp);font-variation-settings:'wdth' 84,'opsz' 60;
  font-weight:800;font-size:1.625rem;line-height:1;letter-spacing:-.035em;color:var(--ice)}
.tier.on .t-price{color:var(--gold-soft)}
.t-each{display:block;font-size:0.90625rem;font-weight:600;color:var(--mist);margin-top:5px}
.t-save{
  display:inline-block;margin-top:7px;font-size:0.875rem;font-weight:800;
  background:var(--gold);color:var(--abyss);padding:3px 11px;border-radius:var(--r-pill);
}
.t-rec{
  position:absolute;top:-11px;left:16px;font-size:0.875rem;font-weight:800;
  background:var(--gold);color:var(--abyss);padding:3px 12px;border-radius:var(--r-pill);
}

.promise b{display:block;font-size:1.0625rem;font-weight:800;line-height:1.4;color:var(--ice)}
.promise p{margin:6px 0 0;font-size:0.96875rem;line-height:1.5;color:var(--mist)}

.cta{
  display:block;width:100%;margin-top:18px;border:0;cursor:pointer;
  background:var(--gold);color:var(--abyss);
  padding:21px 18px;border-radius:var(--r-pill);
  font-family:var(--ui);font-weight:800;font-size:1.1875rem;letter-spacing:-.01em;line-height:1.25;
}
html[lang="zh-Hans"] .cta,html[lang="zh-Hant"] .cta{font-family:var(--cjk);letter-spacing:.04em}
@media (prefers-reduced-motion:no-preference){.cta{transition:transform .15s ease}}
.cta:active{transform:scale(.985)}
.cta:focus-visible{outline:3px solid var(--ice);outline-offset:3px}
/* ------------------------------------------------ the pressed button ----
   A spinner beside the label rather than instead of it: swapping the text for
   "Adding..." reflows the button mid-press, and the label is what a shopper
   is looking at when they wonder whether the tap registered.

   The label keeps its place because the mark is drawn in the padding — the
   button does not resize, so nothing under the thumb moves. */
.cta.is-busy,.dbtn.is-busy,.dr-cta.is-busy{position:relative;cursor:progress}
.cta.is-busy::after,.dbtn.is-busy::after,.dr-cta.is-busy::after{
  content:"";position:absolute;top:50%;right:clamp(14px,4vw,22px);
  width:18px;height:18px;margin-top:-9px;
  border:2.5px solid rgba(7,42,29,.28);border-top-color:var(--ink);
  border-radius:50%;
  animation:dg-spin .62s linear infinite;
}
.dr-cta.is-busy::after{border-color:rgba(7,42,29,.28);border-top-color:var(--ink)}
@keyframes dg-spin{to{transform:rotate(360deg)}}
/* A shopper who has asked for less motion still needs to know it is working,
   so the mark stays and only the spinning stops. */
@media (prefers-reduced-motion:reduce){
  .cta.is-busy::after,.dbtn.is-busy::after,.dr-cta.is-busy::after{
    animation:none;border-top-color:var(--ink);opacity:.65;
  }
}
button.is-busy{opacity:1}

.eta{margin:13px 0 0;text-align:center;font-size:0.96875rem;font-weight:600;color:var(--mist)}
.call{
  display:block;margin:11px 0 0;text-align:center;font-size:1rem;font-weight:700;
  color:var(--gold);text-decoration:underline;text-underline-offset:5px;
}


/* ---------- how to open ---------- */
.how{padding:36px 16px 0}
.how h3{margin:0 0 5px;font-size:1.625rem;line-height:1.08;letter-spacing:-.028em;color:var(--ice)}
.how .sub{margin:0 0 18px;font-size:0.96875rem;color:var(--mist)}
.steps{display:grid;grid-template-columns:1fr 1fr;gap:13px}
.step figure{
  margin:0;position:relative;aspect-ratio:1/1;border-radius:var(--r-card);
  overflow:hidden;background:var(--jade);border:1px solid var(--glass-line);
}
.step figure img{width:100%;height:100%;object-fit:cover;display:block}
.step .n{
  position:absolute;top:10px;left:10px;width:28px;height:28px;border-radius:50%;
  background:var(--gold);color:var(--abyss);display:grid;place-items:center;
  font-family:var(--ui);font-weight:800;font-size:0.9375rem;line-height:1;
}
.step b{display:block;margin:12px 0 4px;font-size:1.0625rem;font-weight:800;color:var(--ice);letter-spacing:-.012em}
.step span{display:block;font-size:0.90625rem;line-height:1.42;color:var(--mist)}

/* ---------- flavour ---------- */
.taste{padding:30px 16px 0}
.taste-h{
  margin:0 4px 10px;font-size:0.875rem;font-weight:700;letter-spacing:.17em;
  text-transform:uppercase;color:var(--gold);
}
html[lang="zh-Hans"] .taste-h,html[lang="zh-Hant"] .taste-h,html[lang="vi"] .taste-h{
  letter-spacing:.04em;text-transform:none;font-size:0.9375rem;
}
.taste h3{margin:0 4px 8px;font-size:1.625rem;line-height:1.08;letter-spacing:-.028em;color:var(--ice)}
.taste .lead{margin:0 4px 20px;font-size:1.03125rem;line-height:1.5;color:var(--mist)}
.meters{
  border:1px solid var(--glass-line);border-radius:var(--r-card);background:var(--glass);
  padding:16px 17px 6px;
}
.meter{margin-bottom:14px}
.meter-top{display:flex;align-items:baseline;justify-content:space-between;margin-bottom:7px}
.meter b{font-size:1rem;font-weight:700;color:var(--ice)}
.meter i{font-style:normal;font-size:0.875rem;font-weight:600;color:var(--mist)}
.track{height:8px;border-radius:99px;background:rgba(232,242,236,.13);overflow:hidden}
.fill{height:100%;border-radius:99px;background:var(--gold);width:0}
@media (prefers-reduced-motion:no-preference){
  .fill{transition:width .8s cubic-bezier(.2,.75,.25,1)}
}
.notes{margin:16px 0 0;padding:0;list-style:none;display:flex;flex-direction:column;gap:9px}
.notes li{
  display:flex;gap:12px;align-items:flex-start;font-size:1rem;line-height:1.45;color:var(--ice);
}
.notes li::before{
  content:"";flex:0 0 auto;width:7px;height:7px;border-radius:50%;background:var(--gold);margin-top:8px;
}
.first-time{
  margin:18px 4px 0;padding-left:15px;border-left:3px solid var(--gold);
}
.first-time b{display:block;font-size:1.03125rem;font-weight:800;color:var(--ice);line-height:1.4}
.first-time p{margin:6px 0 0;font-size:0.96875rem;line-height:1.5;color:var(--mist)}

/* ---------- one flat ground; every block is an element, not a band ---------- */
.buy-wrap{padding:0}
.taste-wrap{margin-top:32px;padding:0}

/* ---------------------------------------------------------- taste shot --
   The flavour photo. Held to 4:3 by aspect-ratio rather than by the file, so
   a merchant who swaps in a taller crop gets a cover fit instead of a jump in
   the page's height. The gold hairline is the same one the buy card uses. */
/* No side margins of its own: the section already sets the measure, and the
   16px this used to add on each side made the photograph 326px against the
   358px stats card directly beneath it — two edges that should have been one.
   The bottom margin is the gap that was missing entirely; the two were touching. */
.taste-shot{
  margin:18px 0 14px;overflow:hidden;
  border-radius:var(--r-card);border:1px solid var(--glass-line);
  background:var(--glass);
}
/* 1:1, this photograph's own shape. Held by aspect-ratio rather than by the
   file, so a merchant swapping in a different crop gets a cover fit instead of
   a jump in the page's height — but the ratio has to match the picture in it.
   It has been wrong twice now: 3:2 took the face off a portrait, then 4:5 was
   left behind when the portrait was replaced by a square studio shot, which
   would have cropped the outer lobes off both sides. */
.taste-shot img{
  display:block;width:100%;height:auto;aspect-ratio:1/1;object-fit:cover;
}
.sold-wrap{margin-top:30px;padding:0}
.sold{margin:0 20px;padding:15px 0;border-top:1px solid var(--glass-line)}

/* tiers: the border does the separating now */
.tier{background:var(--jade);border:1.5px solid rgba(234,244,238,.42)}
.tier.on{
  border-color:var(--gold);background:#175139;
  box-shadow:0 0 0 4px rgba(245,193,54,.2),0 16px 34px -14px rgba(0,0,0,.75);
}

/* conversion text, dialled up */
.t-price{font-size:1.8125rem}
.t-each{font-size:0.96875rem;color:var(--ice);font-weight:700}
.t-save{font-size:0.9375rem;padding:4px 12px}
.t-rec{font-size:0.90625rem;padding:4px 14px}

/* the promise is the one light block on the page */

.cta{font-size:1.25rem;padding:23px 16px}
.eta{
  margin:14px 16px 0;padding:12px 14px;border-radius:var(--r-pill);
  background:var(--jade);border:1px solid rgba(234,244,238,.42);
  font-size:1.03125rem;font-weight:700;color:var(--ice);text-align:center;
}
.call{color:var(--gold);font-size:1.03125rem}

/* flavour + faq blocks get the same treatment */
.meters{border:1.5px solid rgba(234,244,238,.42);background:var(--jade)}
.faq details{border:1.5px solid rgba(234,244,238,.42);background:var(--jade)}
.faq details[open]{background:#175139;border-color:var(--gold)}
.chips div{border:1.5px solid rgba(234,244,238,.42);background:var(--jade)}
.spec{
  background:var(--gold);border:1.5px solid var(--gold);color:var(--abyss);
  font-size:1rem;font-weight:800;letter-spacing:0;
}

/* ---------- guarantee band: full-bleed, zigzag edges echo the box tape ---------- */
.promise{
  position:relative;margin:18px 0 0;padding:16px 18px;
  background:var(--cream);border-radius:var(--r-card);border:1.5px solid var(--gold);
  display:grid;grid-template-columns:auto 1fr;gap:14px;align-items:center;
}
.pr-seal{width:50px;height:50px;flex:0 0 auto}
.pr-copy b{
  display:block;font-family:var(--dsp);font-variation-settings:'wdth' 88,'opsz' 40;
  font-weight:800;font-size:1.1875rem;line-height:1.2;letter-spacing:-.02em;color:#0A3325;
}
.pr-copy p{margin:5px 0 0;font-size:0.96875rem;line-height:1.45;color:#3B5546}
html[lang="zh-Hans"] .pr-copy b,html[lang="zh-Hant"] .pr-copy b{font-family:var(--cjk);font-size:1.3125rem}

/* ---------- section blocking: the fold stays flat, each section below gets its own ground ---------- */

/* HOW TO OPEN — light band. The step photos are bright kitchen shots; cream suits them
   and the change of ground signals "this part is teaching, not selling". */
.how-wrap{background:var(--cream);margin-top:0;padding:30px 0 34px}
.how{padding:0 16px}
.how h3{color:#0A3325}
.how .sub{color:#3B5546}
.how .step figure{border:1.5px solid rgba(10,51,37,.18);background:#E9E3D2}
.how .step b{color:#0A3325}
.how .step span{color:#3B5546}

/* FLAVOUR — deepest ground on the page, so the gold meters carry. */
/* Sits directly under the fold now, so it starts flush with the ombre's last
   pixel; the negative bottom margin closes the sub-pixel line that otherwise
   shows page green between this section and the cream one below it. */
.taste-wrap{background:var(--deep);margin:0 0 -1px;padding:32px 0 34px}
.taste{padding:0 16px}
.taste .meters{background:rgba(234,244,238,.055);border-color:rgba(234,244,238,.3)}
.taste .first-time{border-left-color:var(--gold)}

/* FAQ — back to the page green: a rest between two strong bands. */
.faq{padding:36px 16px 0}

/* FOOTER — dark strip to close the page. */
.sold-wrap{background:var(--deep);margin-top:34px;padding:20px 0}
.sold{margin:0 20px;padding:0;border-top:0}

/* ---------- accepted payment ---------- */
.pay{
  display:flex;justify-content:center;align-items:center;gap:8px;
  margin:18px 16px 0;flex-wrap:wrap;
}
.pay svg{
  width:46px;height:29px;display:block;border-radius:5px;
  box-shadow:0 0 0 1px rgba(234,244,238,.28);
}

/* ---------- faq ---------- */
.faq{padding:34px 16px 0}
.faq-h{
  margin:0 4px 10px;font-size:0.875rem;font-weight:700;letter-spacing:.17em;
  text-transform:uppercase;color:var(--gold);
}
html[lang="zh-Hans"] .faq-h,html[lang="zh-Hant"] .faq-h,html[lang="vi"] .faq-h{
  letter-spacing:.04em;text-transform:none;font-size:0.9375rem;
}
.faq h3{margin:0 4px 18px;font-size:1.625rem;line-height:1.08;letter-spacing:-.028em;color:var(--ice)}
.faq details{
  border:1px solid var(--glass-line);border-radius:var(--r-card);
  background:var(--glass);margin-bottom:10px;overflow:hidden;
}
.faq details[open]{background:rgba(245,193,54,.06);border-color:rgba(245,193,54,.3)}
.faq summary{
  list-style:none;cursor:pointer;position:relative;
  padding:17px 50px 17px 17px;font-size:1.0625rem;font-weight:700;line-height:1.35;color:var(--ice);
}
.faq summary::-webkit-details-marker{display:none}
.faq summary::after{
  content:"";position:absolute;right:19px;top:22px;width:13px;height:8px;
  background:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='13' height='8'%3E%3Cpath d='M1.5 1.5l5 5 5-5' stroke='%23F5C136' stroke-width='2' fill='none' stroke-linecap='round'/%3E%3C/svg%3E") no-repeat center;
}
@media (prefers-reduced-motion:no-preference){
  .faq summary::after{transition:transform .22s ease}
}
.faq details[open] summary::after{transform:rotate(180deg)}
.faq summary:focus-visible{outline:2px solid var(--gold);outline-offset:-3px;border-radius:var(--r-card)}
.faq .ans{margin:0;padding:0 17px 17px;font-size:1rem;line-height:1.6;color:var(--mist)}

.sold{
  margin:26px 20px 0;text-align:center;font-size:0.9375rem;font-weight:600;color:var(--mist);
}

/* ---------- dock ---------- */
.dock{
  position:fixed;left:0;right:0;bottom:0;z-index:40;
  background:rgba(14,66,48,.93);backdrop-filter:blur(14px);
  border-top:1px solid var(--glass-line);
  padding:12px 16px calc(12px + env(safe-area-inset-bottom));
  display:flex;align-items:stretch;gap:14px;max-width:480px;margin:0 auto;
}
/* stretch, not center: centred, the select and the button each size to their
   own text, and in Traditional Chinese the two came out a pixel apart. Sharing
   the row's height makes them the same by construction rather than by luck. */
.dock .d-l,.dock .d-sel,.dock #dbtn{align-self:stretch}
.dock .d-sel{
  flex:1 1 auto;min-width:0;cursor:pointer;
  font-family:var(--ui);font-size:1.0625rem;font-weight:700;color:var(--ice);letter-spacing:-.01em;
  background:var(--jade) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='13' height='8'%3E%3Cpath d='M1.5 1.5l5 5 5-5' stroke='%23F5C136' stroke-width='2' fill='none' stroke-linecap='round'/%3E%3C/svg%3E") no-repeat right 16px center;
  border:1.5px solid var(--glass-line);border-radius:var(--r-pill);
  padding:16px 40px 16px 20px;appearance:none;-webkit-appearance:none;
}
html[lang="zh-Hans"] .dock .d-sel,html[lang="zh-Hant"] .dock .d-sel{font-family:var(--cjk)}
.dock .d-sel option{color:#12291D;background:#F2EEE2;font-weight:600}
.dock .d-sel:focus-visible{outline:2px solid var(--gold);outline-offset:3px}
.dock button{
  flex:0 0 auto;border:0;cursor:pointer;background:var(--gold);color:var(--abyss);
  padding:16px 24px;border-radius:var(--r-pill);
  font-family:var(--ui);font-weight:800;font-size:1.03125rem;letter-spacing:-.01em;
}
.dock button:focus-visible{outline:3px solid var(--ice);outline-offset:3px}

/* ---------- one orchestrated load ---------- */
@media (prefers-reduced-motion:no-preference){
  .rise{animation:rise .72s cubic-bezier(.2,.75,.25,1) both}
  .r1{animation-delay:.04s}.r2{animation-delay:.13s}.r3{animation-delay:.22s}.r4{animation-delay:.34s}
  @keyframes rise{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}
}
/* ============================================================
   Shopify additions — v74 theme build.
   Nothing above this line was changed. Everything below is
   either a state the static mockup never had (sold out, empty
   cart, in-flight request) or a Shopify chrome fix.
   ============================================================ */

[hidden]{display:none !important}

/* sold-out tier: readable, plainly unavailable, not hidden */
.tier.oos{opacity:.5}
.tier.oos .t-price,.tier.oos .t-qty{color:var(--mist)}
.t-oos{
  display:inline-block;margin-top:7px;font-size:0.875rem;font-weight:800;
  background:rgba(234,244,238,.16);color:var(--ice);
  padding:3px 11px;border-radius:var(--r-pill);
}

/* a button waiting on Shopify */
.cta[aria-busy="true"],.dock button[aria-busy="true"],.dr-cta[aria-busy="true"]{
  pointer-events:none;
  opacity:.62;cursor:progress;
}

/* cart errors, and the empty-cart state the mockup had no room for */
.dg-err{
  margin:14px 0 0;padding:12px 14px;border-radius:var(--r-card);
  background:rgba(255,120,90,.1);border:1px solid rgba(255,150,120,.42);
  font-size:0.96875rem;line-height:1.45;color:#FFD9CE;
}
.dr-empty{padding:34px 4px 18px;text-align:center;font-size:1.03125rem;color:var(--mist)}
.dr-empty-cta{
  display:block;width:100%;cursor:pointer;
  padding:16px 18px;border-radius:var(--r-pill);
  background:var(--gold);color:var(--abyss);border:0;
  font-family:var(--ui);font-size:1.0625rem;font-weight:800;letter-spacing:-.01em;
}
@media (prefers-reduced-motion:no-preference){
  .dr-empty-cta{transition:transform .15s ease}
}
.dr-empty-cta:active{transform:scale(.985)}
.dr-empty-cta:focus-visible{outline:3px solid var(--ice);outline-offset:3px}
html[lang="zh-Hans"] .dr-empty-cta,html[lang="zh-Hant"] .dr-empty-cta{font-family:var(--cjk)}
.line + .line{margin-top:18px;padding-top:18px;border-top:1px solid var(--glass-line)}

/* keyboard users need to be able to skip the sticky chrome */
.dg-skip{
  position:absolute;left:-9999px;top:0;z-index:70;
  background:var(--gold);color:var(--abyss);padding:12px 18px;
  border-radius:0 0 var(--r-pill) 0;font-weight:800;text-decoration:none;
}
.dg-skip:focus{left:0}

/* ---------- footer ---------- */
.foot{
  background:var(--deep);margin-top:34px;
  padding:32px 20px 26px;
  border-top:1px solid var(--glass-line);
}
.foot-mark{display:flex;align-items:center;gap:10px}
.foot-mark .mark b{font-size:1.4375rem}
.foot-tag{
  margin:12px 0 0;font-size:1rem;line-height:1.5;color:var(--mist);max-width:36ch;
}

/* contact: the one thing an older shopper most often wants */
.foot-contact{
  margin:22px 0 0;padding:16px 17px 14px;
  background:var(--jade);border:1.5px solid rgba(234,244,238,.42);border-radius:var(--r-card);
}
.foot-call,.foot-mail{
  display:block;text-decoration:none;padding:7px 0;
}
.foot-mail{border-top:1px solid var(--glass-line);margin-top:7px;padding-top:12px}
.foot-call-l{
  display:block;font-size:0.84375rem;font-weight:700;letter-spacing:.14em;
  text-transform:uppercase;color:var(--gold);
}
html[lang="zh-Hans"] .foot-call-l,html[lang="zh-Hant"] .foot-call-l,html[lang="vi"] .foot-call-l{
  letter-spacing:.04em;text-transform:none;font-size:0.90625rem;
}
.foot-call-n{
  display:block;margin-top:3px;font-size:1.25rem;font-weight:800;color:var(--ice);
  letter-spacing:-.01em;word-break:break-word;
}
.foot-call:focus-visible,.foot-mail:focus-visible{outline:2px solid var(--gold);outline-offset:4px;border-radius:8px}
.foot-hours{margin:11px 0 0;font-size:0.9375rem;color:var(--mist)}

.foot-cols{display:flex;flex-wrap:wrap;gap:28px;margin:26px 0 0}
.foot-col{min-width:44%}
.foot-h{
  margin:0 0 10px;font-size:0.84375rem;font-weight:700;letter-spacing:.14em;
  text-transform:uppercase;color:var(--gold);
}
html[lang="zh-Hans"] .foot-h,html[lang="zh-Hant"] .foot-h,html[lang="vi"] .foot-h{
  letter-spacing:.04em;text-transform:none;font-size:0.90625rem;
}
.foot-col ul{margin:0;padding:0;list-style:none}
.foot-col li{margin:0 0 3px}
.foot-col a{
  display:flex;align-items:center;min-height:44px;padding:6px 0;
  font-size:1.03125rem;font-weight:600;
  color:var(--ice);text-decoration:none;
}
.foot-col a:hover{color:var(--gold)}
.foot-col a:focus-visible{outline:2px solid var(--gold);outline-offset:3px;border-radius:6px}

.foot-pay{margin:26px 0 0}
.foot-pay .pay{margin:10px 0 0;justify-content:flex-start}

.foot-base{
  margin:26px 0 0;padding-top:18px;border-top:1px solid var(--glass-line);
}
/* Named apart from .foot-tag — that class already carries the masthead blurb
   at the top of the footer, and reusing it put the same words in both. */
.foot-line{
  margin:0;font-family:var(--dsp);font-variation-settings:'wdth' 90,'opsz' 40;
  font-weight:800;font-size:1.1875rem;line-height:1.25;letter-spacing:-.015em;color:var(--gold);
}
html[lang="zh-Hans"] .foot-line,html[lang="zh-Hant"] .foot-line{
  font-family:var(--cjk);font-weight:700;letter-spacing:.02em;
}
.foot-legal{margin:9px 0 0;font-size:0.90625rem;line-height:1.5;color:var(--mist)}

/* ============================================================
   v1.2 — the buy tiers get room to breathe, and the header
   earns its place. Overrides only; nothing above was edited.
   ============================================================ */

:root{
  --bar:#072A1D;                       /* deeper than the page, so the header reads as chrome */
  --chip:rgba(245,193,54,.13);
  --chip-line:rgba(245,193,54,.34);
}

/* ---------- announcement strip: brushed gold, not flat gold ---------- */
.strip{
  padding:15px 16px;gap:11px;
  font-size:0.96875rem;letter-spacing:.005em;
  background:var(--gold);
  box-shadow:inset 0 -1px 0 rgba(7,42,29,.28);
}
.strip .flag{
  width:27px;height:19px;border-radius:3px;
  box-shadow:0 0 0 1px rgba(7,42,29,.22);
}

/* ---------- bar: darker ground, gold hairline, lift once it sticks ---------- */
.bar{
  padding:14px 16px;
  background:rgba(21,79,55,.94);
  border-bottom:1px solid rgba(245,193,54,.20);
}
@media (prefers-reduced-motion:no-preference){
  .bar{transition:box-shadow .26s ease,background-color .26s ease,border-color .26s ease}
}
.bar.is-stuck{
  background:rgba(21,79,55,.985);
  border-bottom-color:rgba(245,193,54,.34);
  box-shadow:0 14px 30px -18px rgba(0,0,0,.9);
}

.mark b{font-size:1.4375rem;letter-spacing:-.022em}
.mark i{
  color:var(--gold);
  text-shadow:0 0 22px rgba(245,193,54,.34);   /* the gold half catches a little light */
}

/* the two controls become one matched pair */
.bar-r{gap:9px}
.lang,.cartbtn{
  height:44px;
  background-color:rgba(255,255,255,.07);
  border:1.5px solid rgba(234,244,238,.24);
  border-radius:var(--r-pill);
}
.lang{
  padding:0 33px 0 15px;
  font-size:0.96875rem;font-weight:800;
  background-position:right 13px center;
}
.cartbtn{padding:0 13px 0 12px;gap:9px;font-size:0.96875rem;font-weight:800}
.cartbtn svg{width:20px;height:20px}
.cartbtn span{min-width:23px;height:23px;font-size:0.875rem;padding:0 7px}
@media (prefers-reduced-motion:no-preference){
  .lang,.cartbtn{transition:border-color .16s ease,background-color .16s ease}
}
.lang:hover,.cartbtn:hover{border-color:rgba(245,193,54,.55);background-color:rgba(245,193,54,.09)}
.cartbtn:active{transform:scale(.97)}

/* ---------- buy tiers: the cramping was spacing, not layout ---------- */
.buy{padding:28px 16px 0}
.buy .ask{margin:0 4px 18px}
.buy h2{font-size:1.75rem}

.tier{
  gap:16px;
  padding:20px 18px;
  border-radius:24px;
  min-height:104px;
  margin-bottom:14px;
}
/* the recommended badge sits above the top edge — give it somewhere to sit */
.tier:has(.t-rec){margin-top:10px}
.tier.on{
  box-shadow:0 0 0 4px rgba(245,193,54,.18),0 20px 40px -18px rgba(0,0,0,.82);
}
.tier input{width:26px;height:26px;border-width:2px}
.tier input:checked::after{width:14px;height:14px}

.t-qty{font-size:1.5625rem;line-height:1.08}
.t-cn{font-size:0.9375rem;margin-top:6px;line-height:1.38}

/* the weight reads as a spec, so it looks like one */

/* six pips used to wrap onto a second row and look like a mistake */
.pips{gap:4px;margin-top:12px}
.pips svg{width:19px;height:19px}

.t-r{padding-left:4px}
.t-price{font-size:1.875rem}
.t-each{font-size:0.9375rem;margin-top:7px}
.t-save{margin-top:10px;font-size:0.90625rem;padding:5px 12px}
.t-rec{top:-13px;left:18px;font-size:0.90625rem;padding:4px 14px}

/* the blocks that follow the tiers get matching air */
.promise{margin-top:22px;padding:18px 18px;gap:15px}
.cta{margin-top:20px}

/* Both columns start at the top, so the price sits on the title's line instead
   of floating against the middle of the description. */
.tier{align-items:flex-start}
.tier input{margin-top:2px}
.t-r{display:flex;flex-direction:column;align-items:flex-end}
.t-price{line-height:1.02}
.t-save{align-self:flex-end}

/* In Vietnamese "Tiết kiệm $146" pushed the price column to 134px and left the
   description barely 113px to wrap in. The saving is a badge, not a column —
   so it moves to the card's top-right corner, mirroring "Recommended", and the
   text column gets its width back. */
.t-save{
  position:absolute;top:-13px;right:18px;margin-top:0;
  box-shadow:0 6px 14px -6px rgba(0,0,0,.6);
}
.t-r{max-width:44%}
.t-each{line-height:1.32}

/* six pips have to fit the narrowest column any language produces */
.pips{gap:3px}
.pips svg{width:17px;height:17px}

/* A card that carries a corner badge needs clearance above it, or the badge
   crowds the card before it. Cards without one stay tight. */
.tier{margin-bottom:10px}
/* adjacent margins collapse, so this has to cover the badge on its own:
   30px gap minus the badge overhanging 13px leaves 17px of clear space. */
.tier:has(.t-rec),.tier:has(.t-save){margin-top:30px}

/* The hero sat flush against the sticky bar. */
.shot{margin-top:14px}

/* Bigger durians in the buy panel.

   They used to live inside the text column, which at 320px is only ~95px wide,
   so six of them wrapped to a second row at any size worth looking at.

   Giving the card a grid rather than a flex row fixes it properly: the pips get
   a row of their own spanning the text and price columns, and the empty first
   cell lines them up under the title for free. Flex-wrap was the wrong tool —
   at 320px it dropped the price below the description instead of only moving
   the pips. */
.tier{
  display:grid;
  grid-template-columns:auto minmax(0,1fr) auto;
  grid-template-areas:
    "radio text  price"
    ".     pips  pips";
  column-gap:16px;
  align-items:start;
}
.tier > input{grid-area:radio}
.t-l{grid-area:text;min-width:0}
.t-r{grid-area:price;justify-self:end;max-width:none}
.pips{
  grid-area:pips;
  margin:15px 0 0;padding:0;
  gap:4px;flex-wrap:nowrap;
}
.pips svg{width:24px;height:24px}

/* ============================================================
   Selected tier — treatment 02 "gold wash", over 01's ring.

   The card's whole surface warms instead of only its edge, so the choice
   reads before any of the words do. That matters here: the buyer is often
   older, often reading a second language, and often on a phone outdoors,
   where a hairline or a glow is the first thing to disappear.

   The ring stays underneath. The wash alone loses the card's edge against
   the page ground; the ring holds it. One change, read two ways.
   ============================================================ */

:root{--jade-lift:#175139}

.tier.on{
  border-color:var(--gold);
  background:
    linear-gradient(148deg,
      rgba(245,193,54,.34) 0%,
      rgba(245,193,54,.12) 52%,
      rgba(245,193,54,0)   82%),
    var(--jade-lift);
  box-shadow:
    0 0 0 4px rgba(245,193,54,.18),
    0 20px 40px -18px rgba(0,0,0,.82);
}

/* The wash warms the ground under the description, which cost it contrast:
   mist on the washed card measured 4.27, under the 4.5 floor. On a card where
   the title, the pips and the chip all brighten, the description brightening
   too is the consistent answer as well as the legible one. */
.tier.on .t-cn{color:var(--ice)}

/* ============================================================
   Tiers, packed tighter.

   They were four stacked rows — title, description, weight, durians — plus a
   104px floor, so every card was far taller than its content. The weight chip
   was also wrapping to two lines, which read as a bug.
   ============================================================ */

.tier{
  grid-template-areas:
    "radio text  price"
    ".     meta  meta";
  min-height:0;
  padding:18px 18px 16px;
}

.t-meta{
  grid-area:meta;
  display:flex;align-items:center;flex-wrap:wrap;
  gap:10px 12px;
  margin-top:12px;
}

.pips{margin:0}

/* the description carries the height when it wraps, so keep it tight */
.t-cn{margin-top:5px;line-height:1.34}

/* ============================================================
   Header: menu | logo | cart.

   Three grid columns with equal flexible sides puts the wordmark on the true
   centre of the page rather than the centre of the space left over.
   ============================================================ */

.bar{
  display:grid;
  grid-template-columns:1fr auto 1fr;
  align-items:center;
  gap:10px;
}
.logo{
  grid-column:2;
  justify-self:center;
  text-decoration:none;
  gap:10px;
}
.bar-r{grid-column:3;justify-self:end}
.navbtn{
  grid-column:1;justify-self:start;
  display:grid;place-items:center;
  width:44px;height:44px;flex:0 0 auto;cursor:pointer;
  background-color:rgba(255,255,255,.07);
  border:1.5px solid rgba(234,244,238,.24);
  border-radius:var(--r-pill);
  color:var(--ice);padding:0;
}
.navbtn svg{width:21px;height:21px;display:block}
@media (prefers-reduced-motion:no-preference){
  .navbtn{transition:border-color .16s ease,background-color .16s ease}
}
.navbtn:hover{border-color:rgba(245,193,54,.55);background-color:rgba(245,193,54,.09)}
.navbtn:focus-visible{outline:2px solid var(--gold);outline-offset:3px}



/* ---------- the menu drawer ---------- */
.nav-scrim{
  position:fixed;inset:0;z-index:60;
  background:rgba(4,22,15,.76);backdrop-filter:blur(3px);
  opacity:0;pointer-events:none;
}
.nav-scrim.on{opacity:1;pointer-events:auto}
@media (prefers-reduced-motion:no-preference){.nav-scrim{transition:opacity .28s ease}}

.navdrawer{
  position:fixed;top:0;left:0;bottom:0;z-index:61;width:min(360px,86vw);
  background:var(--abyss);border-right:1px solid var(--glass-line);
  display:flex;flex-direction:column;transform:translateX(-102%);
  box-shadow:24px 0 60px -20px rgba(0,0,0,.7);
}
.navdrawer.on{transform:none}
@media (prefers-reduced-motion:no-preference){
  .navdrawer{transition:transform .34s cubic-bezier(.2,.75,.25,1)}
}
.nav-head{
  display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:18px 18px 16px;border-bottom:1px solid var(--glass-line);flex:0 0 auto;
}
.nav-mark{display:flex;align-items:center;gap:10px}
.nav-mark .mark b{font-size:1.25rem}
.nav-x{
  background:var(--glass);border:1px solid var(--glass-line);color:var(--ice);
  width:40px;height:40px;border-radius:50%;cursor:pointer;
  display:grid;place-items:center;flex:0 0 auto;padding:0;
}
.nav-x svg{width:19px;height:19px;display:block}
.nav-x:focus-visible{outline:2px solid var(--gold);outline-offset:3px}

.nav-body{flex:1 1 auto;overflow-y:auto;padding:18px 18px 10px;-webkit-overflow-scrolling:touch}
.nav-h{
  margin:0 0 10px;font-size:0.8125rem;font-weight:700;letter-spacing:.16em;
  text-transform:uppercase;color:var(--gold);
}
html[lang="zh-Hans"] .nav-h,html[lang="zh-Hant"] .nav-h,html[lang="vi"] .nav-h{
  letter-spacing:.04em;text-transform:none;font-size:0.90625rem;
}
.nav-h + .nav-h,.nav-langs + .nav-h,.nav-links + .nav-h{margin-top:26px}

.nav-langs{display:grid;grid-template-columns:1fr 1fr;gap:9px}
.nav-lang{
  cursor:pointer;padding:13px 10px;border-radius:14px;
  background:var(--jade);border:1.5px solid rgba(234,244,238,.24);
  color:var(--ice);font-family:var(--ui);font-size:0.96875rem;font-weight:700;
  text-align:center;
}
@media (prefers-reduced-motion:no-preference){
  .nav-lang{transition:border-color .16s ease,background .16s ease,color .16s ease}
}
.nav-lang[aria-pressed="true"]{
  border-color:var(--gold);color:var(--gold-soft);
  background:linear-gradient(148deg,rgba(245,193,54,.26),rgba(245,193,54,0) 80%),var(--jade-lift);
}
.nav-lang:focus-visible{outline:2px solid var(--gold);outline-offset:3px}

.nav-links{display:flex;flex-direction:column}
.nav-links a{
  display:flex;align-items:center;justify-content:space-between;gap:10px;
  min-height:44px;padding:16px 2px;font-size:1.09375rem;font-weight:700;color:var(--ice);
  text-decoration:none;border-bottom:1px solid var(--glass-line);
}
.nav-links a:last-child{border-bottom:0}
.nav-links a::after{
  content:"";width:8px;height:13px;flex:0 0 auto;opacity:.55;
  background:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='13'%3E%3Cpath d='M1.5 1.5L6.5 6.5L1.5 11.5' stroke='%23F5C136' stroke-width='2' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") no-repeat center;
}
.nav-links a:hover{color:var(--gold)}
.nav-links a:focus-visible{outline:2px solid var(--gold);outline-offset:-2px;border-radius:8px}
.nav-small a{font-size:0.96875rem;font-weight:600;color:var(--mist);padding:12px 2px}

.nav-foot{
  flex:0 0 auto;padding:14px 18px calc(16px + env(safe-area-inset-bottom));
  border-top:1px solid var(--glass-line);display:flex;flex-direction:column;gap:10px;
}
.nav-call{
  display:flex;align-items:center;gap:11px;text-decoration:none;
  color:var(--ice);font-size:1.03125rem;font-weight:700;word-break:break-word;
}
.nav-call svg{width:19px;height:19px;flex:0 0 auto;color:var(--gold)}
.nav-call:focus-visible{outline:2px solid var(--gold);outline-offset:3px;border-radius:8px}

/* ---------- standalone pages: FAQ and contact ---------- */
.page-body{margin:16px 0 0;font-size:1.03125rem;line-height:1.6;color:var(--mist)}
.page-body a{color:var(--gold)}
.faq-page{padding:22px 0 0}
.form-h{margin:30px 0 14px;font-size:1.5rem;letter-spacing:-.028em;color:var(--ice)}

.dg-form{display:flex;flex-direction:column;gap:14px}
.fld{display:block}
.fld-l{
  display:block;margin:0 0 7px;font-size:0.9375rem;font-weight:700;color:var(--mist);
}
.fld input,.fld textarea{
  width:100%;display:block;
  font-family:var(--ui);font-size:1.0625rem;font-weight:600;color:var(--ice);
  background:var(--jade);border:1.5px solid rgba(234,244,238,.28);
  border-radius:16px;padding:15px 16px;
  -webkit-appearance:none;appearance:none;
}
.fld textarea{border-radius:18px;line-height:1.5;resize:vertical;min-height:130px}
.fld input::placeholder,.fld textarea::placeholder{color:rgba(173,200,184,.7)}
.fld input:focus-visible,.fld textarea:focus-visible{
  outline:none;border-color:var(--gold);
  box-shadow:0 0 0 4px rgba(245,193,54,.16);
}
html[lang="zh-Hans"] .fld input,html[lang="zh-Hant"] .fld input,
html[lang="zh-Hans"] .fld textarea,html[lang="zh-Hant"] .fld textarea{font-family:var(--cjk),var(--ui)}

.form-ok{
  margin:0;padding:14px 16px;border-radius:var(--r-card);
  background:rgba(245,193,54,.1);border:1px solid rgba(245,193,54,.4);
  font-size:1rem;font-weight:700;color:var(--gold-soft);
}

/* Shopify draws the official brand marks; match them to the row's sizing. */
.pay .pay-icon{
  width:46px;height:29px;display:block;
  border-radius:5px;background:#fff;
  box-shadow:0 0 0 1px rgba(234,244,238,.28);
}
.pay{gap:8px;row-gap:9px}

/* ---------- tiers, with the weight badge in place of the description ---------- */
.tier{padding:20px 18px}
.t-cn{margin-top:6px}
.t-meta{margin-top:13px}

/* ---------- proof, on the photograph ---------- */
.shot{position:relative}
/* A solid gold flag rather than a glass pill: on a photograph of fruit the
   translucent version kept picking up whatever was behind it, and the number
   is the thing worth reading — so it gets the size and the ink is dark on gold.
   The notch cut into the left edge is what stops it reading as a button. */

/* The glint. clip-path clips descendants too, so the band is cut to the flag
   silhouette for free and needs no overflow container of its own. */

/* The only permanently-running animation on the page, and it sits inside an
   element carrying BOTH a filter and a clip-path — so every frame re-rasterises
   that whole subtree, on screen or not, for the life of the page. Paused unless
   the gallery is actually in view; the observer in dg74.js flips the class. */
@media (prefers-reduced-motion:no-preference){


}
@keyframes badge-glint{
  0%{transform:translateX(-135%)}
  22%,100%{transform:translateX(135%)}
}



/* The claim belongs to the lead shot. Swap to any other gallery image and it
/* Shop Pay Installments. Shopify renders the widget; it arrives light-on-white,
   so it gets a plate rather than being left to disappear into the dark green. */
.dg-terms{margin:14px 0 0}
.dg-terms:empty{display:none}
/* Same treatment as the "New to durian?" note: a gold rule down the left and
   nothing else, so a message from Shopify reads as part of the page instead of
   a boxed advert. The ground stays DARK — the widget's text colour is
   inherited and would have worked either way, but the Shop Pay wordmark is a
   fixed WHITE SVG inside the component's shadow DOM that no theme CSS can
   reach, so the cream plate it used to sit on erased the one mark that
   identifies the offer. */
.dg-terms shopify-payment-terms{
  display:block;background:var(--ink);color:var(--ice);
  border-left:3px solid var(--gold);
  border-radius:0 var(--r-card) var(--r-card) 0;
  padding:14px 16px 14px 15px;
  font-size:0.96875rem;line-height:1.5;
  color-scheme:dark;   /* honoured by the widget's own light/dark assets */
}
.dg-terms shopify-payment-terms a{color:var(--gold);text-underline-offset:2px}

/* ============================================================
   The announcement bar sticks with the header and rotates.

   Both bars live in one sticky wrapper rather than each sticking on its own:
   the strip's height changes with the language, so a hard-coded top offset on
   the header would leave a gap in one language and overlap in another.
   ============================================================ */

/* The header is a floating card rather than a full-bleed band: it gets the
   page's own side gutter, one radius around both rows, and it keeps a gap at
   the top once it sticks so the page visibly runs underneath it. The wrapper
   owns the radius, so neither row needs corners of its own. */

.bar.is-stuck{border-bottom-color:transparent;box-shadow:0 18px 34px -20px rgba(0,0,0,.9)}

.strip{
  gap:10px;
  padding:13px 14px;
  font-size:clamp(0.78125rem,3.7vw,0.96875rem);
  overflow:hidden;
}
.strip .flag{
  width:24px;height:17px;
  transition:opacity .2s ease;
}
/* icons that are not the flag are line art, so they take the ink colour */
.strip .flag.ico{
  width:19px;height:19px;color:var(--abyss);border-radius:0;box-shadow:none;
}
.strip-track{
  display:block;overflow:hidden;
  min-height:1.35em;line-height:1.35;
  flex:0 1 auto;min-width:0;
}
.strip-msg{
  display:block;white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis;
}
/* The number in the bar dials. Inheriting the strip's colour rather than
   taking a link colour, because on a gold band a blue link would read as a
   mistake — the underline is what says it is tappable. */
/* The number in the bar is a phone link, and it was 18px tall — the height of
   its own text. On a strip that already has 13px of padding above and below
   it, the target can simply claim that padding: the link grows to the full
   height of the band without the band growing at all. */
/* inline-BLOCK, not inline-flex. The line is built as three nodes — the words,
   a <b> holding the number, then the tail — and in a flex container each text
   node becomes an anonymous flex item whose leading and trailing whitespace is
   stripped. The space before the number vanished and the bar read
   "Call or text949-903-5005". Nothing was wrong with the copy; the container
   was eating the space.

   The 44px tap target survives the change: the padding provides it, and
   min-height applies to an inline-block just as it did to the flex box. */
.strip-tel{
  display:inline-block;min-height:44px;
  padding:13px 4px;margin:-13px -4px;
  color:inherit;text-decoration:none;
}
.strip-tel b{font-weight:900;text-decoration:underline;text-underline-offset:2px;
  text-decoration-thickness:1.5px}
/* Both directions are animations. They used to be a transition out and an
   animation in, and the two fought: taking .out off returned the element to
   its resting transform, so the transition ran it back DOWN from -120% at the
   same moment the entrance animation ran it UP from +120%. Every line crossed
   the bar twice before settling, which is the double blink. A transition
   animates whatever changes; an animation states exactly what should happen.
   For a swap that is replacing one string with another, the second is the
   right tool and the first is a trap. */
@media (prefers-reduced-motion:no-preference){
  .strip-msg.out{animation:tape-out .3s cubic-bezier(.4,0,1,1) both}
  .strip-msg.in{animation:tape-in .34s cubic-bezier(.2,.75,.25,1) both}
  @keyframes tape-out{from{transform:none;opacity:1}to{transform:translateY(-115%);opacity:0}}
  @keyframes tape-in{from{transform:translateY(115%);opacity:0}to{transform:none;opacity:1}}
}

/* Nine methods wrap 7 + 2 on a flex row, which reads as an accident. A
   five-column grid gives an even 5 + 4 at any width the page allows. */
.pay{
  display:grid;
  grid-template-columns:repeat(5,minmax(0,1fr));
  gap:8px;
  justify-items:center;align-items:center;
}
.pay .pay-icon,.pay > svg{
  width:100%;max-width:46px;height:auto;aspect-ratio:46 / 29;
}
.foot-pay .pay{max-width:280px}

/* True centring needs the two side columns to be equal. With plain 1fr the
   cart's intrinsic width (80px) overflows its share and squeezes the menu
   side to 57px, pushing the wordmark 11px off centre. A shared minimum makes
   both sides match; below 360px the durian steps out so the wordmark still
   fits between them. */
.bar{grid-template-columns:minmax(80px,1fr) auto minmax(80px,1fr)}
@media (max-width:359px){
  .bar .mark b{font-size:1.1875rem}
}

/* The wordmark carries the header on its own now. */
.nav-mark .mark b{font-size:1.3125rem}
.foot-mark .mark b{font-size:1.5rem}

/* ============================================================
   Tiers, packed down to what a buyer needs.

   The card was 157px tall while its content needed about 100. The price column
   (price + "each" = 57px) set row one's height, and the title beside it is only
   27px, so ~30px sat empty; the durians then took a whole extra row below.

   Putting the specs back under the title fills the space the card was already
   paying for, and the six drawn durians become one photograph with a count.
   ============================================================ */

.tier{
  grid-template-areas:"radio text price";
  padding:16px 16px 15px;
  margin-bottom:8px;
  border-radius:22px;
}
.tier:has(.t-rec),.tier:has(.t-save){margin-top:28px}

.t-meta{
  display:flex;align-items:center;flex-wrap:wrap;
  gap:8px 10px;margin-top:9px;
}
.t-qty{font-size:1.5rem}
.t-cn{margin-top:5px;font-size:0.90625rem}

/* one photograph, and how many of them you get */
.t-count{
  display:inline-flex;align-items:center;gap:5px;
  padding:3px 10px 3px 4px;border-radius:var(--r-pill);
  background:rgba(234,244,238,.07);border:1px solid rgba(234,244,238,.18);
}
.t-count img{
  width:24px;height:24px;display:block;flex:0 0 auto;
  object-fit:contain;
}
.t-count b{
  font-size:0.84375rem;font-weight:800;color:var(--mist);
  letter-spacing:.01em;font-variant-numeric:tabular-nums;
}
.tier.on .t-count{background:rgba(245,193,54,.13);border-color:rgba(245,193,54,.34)}
.tier.on .t-count b{color:var(--gold-soft)}

.t-price{font-size:1.75rem}
.t-each{font-size:0.90625rem;margin-top:5px}
.t-save{top:-12px;right:16px;font-size:0.875rem;padding:4px 11px}
.t-rec{top:-12px;left:16px;font-size:0.875rem;padding:4px 12px}

/* ============================================================
   The fold, condensed — fewer pixels between landing and choosing.

   Nothing is removed: the hero, the thumbnails, the rating, the headline, the
   spec pill and the three promises all stay. They are just no longer spaced
   like a page with room to spare.
   ============================================================ */

/* The hero keeps its square crop on a tall phone and gives some back on a
   short one, rather than eating a fixed half of every screen. */
.shot{max-height:44vh}
.shot-slide img{object-position:center}

.thumbs{--g:6px;padding:7px 16px 5px}
.thumbs figure{border-radius:10px}

.head{padding:16px 20px 0}
.rating{margin:0 0 9px}
.lede{margin:8px 0 0;font-size:0.96875rem;line-height:1.45}

.spec{margin:11px 20px 0;padding:10px 16px}

.buy{padding:20px 16px 0}
.buy .ask{margin:0 4px 14px}

/* A little more off the top of the fold. */
.shot{max-height:40vh}
.thumbs{--g:6px}
.thumbs figure{flex:0 0 calc((100% - 5 * var(--g)) / 6)}

/* ============================================================
   Buy panel, rebuilt to the mockup.

   Two rows per card. Top: radio, box name, price, per-unit price. Bottom: the
   fruit you actually get, a count, and the weight. Both rows start at the
   card's left edge, so the eye runs straight down.
   ============================================================ */

.buy .ask{align-items:baseline;margin:0 4px 12px}
.buy h2{font-size:1.5rem;letter-spacing:-.03em}
.buy .hint{
  font-size:0.75rem;font-weight:800;letter-spacing:.17em;text-transform:uppercase;
  color:var(--mist);white-space:nowrap;
}
html[lang="zh-Hans"] .buy .hint,html[lang="zh-Hant"] .buy .hint,html[lang="vi"] .buy .hint{
  letter-spacing:.04em;text-transform:none;font-size:0.84375rem;
}

.tier{
  display:flex;flex-direction:column;gap:12px;
  align-items:stretch;
  padding:16px;border-radius:20px;
  min-height:0;margin-bottom:9px;
}
.tier:has(.t-rec),.tier:has(.t-save){margin-top:26px}

/* ---- top row ---- */
.t-top{display:flex;align-items:flex-start;gap:12px}
.tier > .t-top > input{margin-top:1px}
.t-l{flex:1 1 auto;min-width:0;display:block}
.t-r{
  flex:0 0 auto;display:flex;flex-direction:column;align-items:flex-end;
  text-align:right;max-width:none;padding-left:4px;
}
.t-qty{font-size:1.375rem;line-height:1.12}
.t-price{font-size:1.875rem;line-height:1}
.t-each{font-size:0.9375rem;font-weight:600;color:var(--mist);margin-top:4px}
.tier.on .t-each{color:rgba(255,220,128,.85)}

/* ---- bottom row: the fruit, the count, the weight ---- */
.t-bottom{
  display:flex;align-items:center;justify-content:space-between;
  gap:10px;flex-wrap:wrap;
}
.t-fruit{display:flex;align-items:center;gap:9px;min-width:0}
.t-fruit-row{display:flex;align-items:flex-end;gap:2px}
.t-fruit-row img{
  height:clamp(28px,8vw,38px);width:auto;display:block;flex:0 0 auto;
  filter:drop-shadow(0 3px 5px rgba(0,0,0,.45));
}
.t-x{
  flex:0 0 auto;
  background:var(--gold);color:var(--abyss);
  font-size:0.875rem;font-weight:800;letter-spacing:.01em;
  padding:4px 11px;border-radius:var(--r-pill);
  font-variant-numeric:tabular-nums;
}
.tier:not(.on) .t-x{background:rgba(245,193,54,.9)}

/* ---- corner badges ---- */
.t-rec{top:-12px;left:14px;font-size:0.84375rem;padding:4px 12px}
.t-save{top:-12px;right:14px;font-size:0.84375rem;padding:4px 12px}
/* "Best value" used to be outlined so it would sit behind "most popular".
   It read as disabled next to the filled one, so both are filled now — the
   selected card's gold wash is what separates the chosen tier, not the badge. */
/* on the gold-washed card a gold save badge disappears — it goes pale instead */
.tier.on .t-save{background:var(--cream);color:var(--abyss)}

/* The gallery runs the full width of the page column. */
.shot{margin-left:0;margin-right:0;border-radius:0;max-height:46vh}

/* Gallery: a centred square with the page's own side margin and corner radius,
   and a thumbnail strip that lines up with it, five across. */
.shot{
  margin:14px 16px 0;
  border-radius:var(--r-card);
  max-height:none;
  aspect-ratio:1 / 1;
}
.thumbs{--g:7px;padding:8px 16px 5px}
.thumbs figure{flex:0 0 calc((100% - 4 * var(--g)) / 5);border-radius:12px}

/* Full-bleed and square: the header runs the whole width of the page column
   with no corner on any edge. The bottom is a row of husk spikes rather than a
   rule — the teeth are what separate the header from the page now, so the old
   gold hairline stays off. The wrapper reserves their depth as padding so they
   hang into space of their own instead of over the gallery. */
.topbar{
  position:sticky;top:0;z-index:50;
  padding-bottom:var(--teeth);
  /* The padding is the band the spikes hang into, so the background is clipped
     to the CONTENT box: the notches between the teeth stay transparent and the
     page still shows through them, but the strip/bar area is backed again.
     Leaving it fully unpainted let a sub-pixel sticky seam at the very top
     expose the scrolling page — read as a transparent gap above the
     announcement bar, and as a shimmer while scrolling. It is gold rather than
     the page colour so that seam, if it ever shows, lands inside the gold
     strip instead of drawing a dark line across it. */
  background:var(--gold);
  background-clip:content-box;
  /* Own compositor layer: the header is repainted on every scroll frame, and
     promoting it stops it being re-rasterised at fractional offsets. */
  transform:translateZ(0);
}
.bar{position:relative}        /* the wrapper does the sticking; this hangs the teeth */
/* Opaque, and no lift. Both were written for a bar with a straight bottom
   edge: the shadow is cast from that rectangle, so once the spikes were added
   it fell across and beside them as a dark band; and the translucency + blur
   let whatever scrolled underneath tint the bar, which put a visible seam
   between it and the solid teeth — read as a gap. The spikes ARE the edge
   treatment now, so the colour has to match them exactly and nothing else
   should sit under the join. */
.bar,.bar.is-stuck{
  background:#154E37;
  -webkit-backdrop-filter:none;backdrop-filter:none;
  box-shadow:none;
}
.strip{border-radius:0}
.bar{border-radius:0;border-bottom:0}

/* One tooth, stamped along the edge as a repeating BACKGROUND rather than a
   mask. Visually identical; a mask makes the browser rasterise the strip into
   a separate buffer and re-composite it every time the sticky header moves,
   which is exactly once per scroll frame. A background-image is just pixels.
   The fill colour is baked into the SVG, so it must be kept equal to .bar. */
.topbar{--teeth:13px;--tooth:27px}
.bar::after{
  content:"";position:absolute;left:0;right:0;pointer-events:none;
  /* Overlapped 1px into the bar: the path's top edge antialiases, and at
     exactly top:100% that row renders half-covered — a hairline of daylight
     along the join. The triangle is full width at its top, so the overlapping
     row is solid and buries the seam. */
  top:calc(100% - 1px);
  height:calc(var(--teeth) + 1px);
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 27 14' preserveAspectRatio='none'%3E%3Cpath d='M0 0h27L13.5 14z' fill='%23154E37'/%3E%3C/svg%3E");
  background-repeat:repeat-x;
  background-position:top left;
  background-size:var(--tooth) 100%;
}

/* ---------- wordmark left with its claim, controls right ---------- */
.bar{
  display:flex;align-items:center;justify-content:space-between;gap:12px;
  grid-template-columns:none;
}
.logo{
  grid-column:auto;justify-self:auto;
  display:flex;flex-direction:column;align-items:flex-start;gap:7px;
  min-width:0;
}
.bar .mark b{font-size:1.25rem;letter-spacing:-.005em;color:#fff}
.mark-tag{
  display:block;color:var(--gold);
  font-family:var(--mark);font-weight:700;font-size:0.78125rem;
  letter-spacing:.005em;line-height:1;
}
html[lang="zh-Hans"] .mark-tag,html[lang="zh-Hant"] .mark-tag{font-family:var(--cjk);font-size:0.78125rem}
.bar-r{grid-column:auto;justify-self:auto;gap:4px;flex:0 0 auto}

/* Bare icons. The pill and the ring were carrying a centred logo's symmetry;
   with the wordmark holding the left they only added noise. The 44px box
   stays — it is the tap target, not decoration. */
.bar .navbtn,.bar .cartbtn{
  width:44px;height:44px;padding:0;
  display:grid;place-items:center;
  background:none;border:0;border-radius:var(--r-pill);
  position:relative;color:#fff;
}
.bar .cartbtn svg{width:19px;height:19px}
.bar .navbtn svg{width:21px;height:21px}
.bar .navbtn:hover,.bar .cartbtn:hover{background-color:rgba(245,193,54,.12);border-color:transparent}
/* The count is a mark on the bag, not a number beside it — and an empty cart
   has nothing to say, so it only appears once there is something in it. */
.bar .cartbtn #cartn{
  display:none;position:absolute;top:5px;right:4px;
  min-width:16px;height:16px;padding:0 4px;
  font-size:0.6875rem;line-height:16px;
}
.bar .cartbtn #cartn.on{display:block}
/* restated here because the small-screen rule further up now loses on order */
@media (max-width:359px){
  .bar .mark b{font-size:1.125rem}
  .mark-tag{font-size:0.65625rem}
  .bar-r{gap:0}
  .topbar{--tooth:23px;--teeth:11px}
}

/* ---------- the guarantee reads as a stamped seal, not a notice ---------- */
/* Cream made it the loudest thing in a dark buy panel — louder than the price
   it sits under. Dark card, gold hairline, and the claim folded into one
   sentence with the promise itself as the only gold words. */
.promise{
  background:var(--ink);
  border:1px solid rgba(245,193,54,.45);
  padding:19px 21px;gap:17px;
}
.pr-seal{
  width:62px;height:62px;flex:0 0 auto;
  filter:drop-shadow(0 4px 10px rgba(0,0,0,.35));
}
.pr-copy{
  margin:0;font-family:var(--ui);
  font-size:1.0625rem;line-height:1.45;color:var(--ice);
}
.pr-copy b{
  font-family:inherit;font-variation-settings:normal;
  font-weight:800;font-size:inherit;line-height:inherit;letter-spacing:0;
  color:var(--gold);
}
html[lang="zh-Hans"] .pr-copy,html[lang="zh-Hant"] .pr-copy{font-family:var(--cjk);font-size:1.03125rem}
html[lang="zh-Hans"] .pr-copy b,html[lang="zh-Hant"] .pr-copy b{font-family:inherit;font-size:inherit}

/* ------------------------------------------- proof, in the fold ----
   A scrolling row of photographs of the fruit on somebody's table. It is
   deliberately wider than the screen: a strip that ends inside the viewport
   reads as all there is, and one that runs off the edge says there are more.

   The thumbnails are a hair under a third of the width so the sixth is cut
   rather than aligned, which is the cheapest way to say "keep going" without
   drawing an arrow. Scroll snapping makes that pleasant rather than fiddly.

   No JavaScript here: each button carries the class the review photo viewer
   already delegates on. */
.proof{margin:clamp(16px,3vw,22px) 0 0}
/* The claim, set as a claim: ice rather than mist, and heavier than the line
   under it, so the eye takes the number first and the description second. */
.proof-lead{
  margin:0 0 2px;font-family:var(--ui);
  font-size:0.96875rem;font-weight:800;letter-spacing:-.005em;color:var(--ice);
}
html[lang^="zh"] .proof-lead{font-family:var(--cjk),var(--ui);letter-spacing:0}
.proof-h{
  margin:0 0 10px;font-family:var(--ui);
  font-size:0.84375rem;font-weight:600;letter-spacing:.01em;color:var(--mist);
}
html[lang^="zh"] .proof-h{font-family:var(--cjk),var(--ui)}
.proof-strip{
  display:flex;gap:8px;margin:0;padding:0 0 2px;list-style:none;
  overflow-x:auto;overflow-y:hidden;
  scroll-snap-type:x proximity;-webkit-overflow-scrolling:touch;
  scrollbar-width:none;
}
.proof-strip::-webkit-scrollbar{display:none}
.proof-strip > li{flex:0 0 auto;scroll-snap-align:start}
/* Scoped to .proof deliberately. These buttons also carry .rev-shot — that is
   how they reach the photo viewer without any script of their own — and
   .rev-shot pins a 74px square for the review grid further down this file.
   Same specificity and later in the cascade, so it won: the strip rendered as
   squares whatever aspect-ratio was asked for here. One extra class settles
   it, and borrowing the viewer stays free. */
.proof .proof-shot{
  display:block;padding:0;border:0;cursor:zoom-in;background:none;
  width:clamp(84px,23vw,100px);height:auto;aspect-ratio:3/4;
  border-radius:12px;overflow:hidden;
  outline:1px solid rgba(234,244,238,.14);outline-offset:-1px;
}
.proof .proof-shot img{display:block;width:100%;height:100%;object-fit:cover}
.proof .proof-shot:focus-visible{outline:2px solid var(--gold);outline-offset:2px}
@media (prefers-reduced-motion:no-preference){
  .proof .proof-shot{transition:transform .16s ease}
  .proof .proof-shot:hover{transform:translateY(-2px)}
}

/* ---------- first-visit language gate ---------- */
/* Hidden unless <html> carries .dg-gate, which the section's inline script
   adds before this paints. No script, no class, no dialog — so the gate can
   never strand a visitor who cannot dismiss it. */
.lang-gate{display:none}
html.dg-gate .lang-gate{
  display:grid;place-items:center;
  position:fixed;inset:0;z-index:120;
  padding:24px;
  background:rgba(7,42,29,.93);
}
@supports (backdrop-filter:blur(6px)){
  html.dg-gate .lang-gate{background:rgba(7,42,29,.82);backdrop-filter:blur(6px)}
}
html.dg-gate{overflow:hidden}
.lg-card{
  width:100%;max-width:340px;text-align:center;
  background:var(--ink);border:1px solid rgba(245,193,54,.4);
  border-radius:var(--r-panel);padding:30px 22px 24px;
}
/* One image where an icon and a wordmark used to be stacked. Sized against
   the viewport rather than fixed, because the card it sits in is itself
   clamped and a fixed logo crowded it on a 4.7in screen. The intrinsic
   width/height on the tag keeps its space reserved while it decodes. */
.lg-logo{
  display:block;margin:0 auto 4px;
  width:clamp(104px,29vw,128px);height:auto;
}
.lg-h{
  margin:9px 0 20px;font-family:var(--ui);
  font-size:0.8125rem;font-weight:600;letter-spacing:.02em;color:var(--mist);
}
.lg-opts{display:grid;gap:9px}
.lg-opts button{
  width:100%;cursor:pointer;
  padding:15px 16px;border-radius:var(--r-pill);
  background:var(--glass);border:1.5px solid var(--glass-line);
  color:var(--ice);font-family:var(--ui);font-size:1.03125rem;font-weight:700;
}
.lg-opts button[lang="zh-Hans"],.lg-opts button[lang="zh-Hant"]{font-family:var(--cjk)}
@media (prefers-reduced-motion:no-preference){
  .lg-opts button{transition:border-color .16s ease,background-color .16s ease}
}
.lg-opts button:hover{border-color:rgba(245,193,54,.6);background-color:rgba(245,193,54,.1)}
.lg-opts button:focus-visible{outline:2px solid var(--gold);outline-offset:3px}

/* ---------- reviews ---------- */
.revs-wrap{padding:0 16px}
.revs{margin:34px 0 0}
.revs-eye{
  margin:0 0 9px;font-size:0.8125rem;font-weight:800;letter-spacing:.14em;
  text-transform:uppercase;color:var(--gold);
}
.revs h3{margin:0;font-size:1.8125rem;line-height:1.1;letter-spacing:-.02em;color:var(--ice)}

/* The score and the histogram are one card, because either alone invites the
   question the other answers: 4.9 of what, and out of how many. */
.revs-summary{
  margin-top:16px;padding:18px;
  background:var(--glass);border:1px solid var(--glass-line);border-radius:var(--r-card);
  display:grid;gap:16px;
}
@media (min-width:520px){.revs-summary{grid-template-columns:auto 1fr;gap:24px;align-items:center}}
.revs-score{display:flex;flex-direction:column;align-items:flex-start;gap:6px}
.revs-avg{
  font-family:var(--dsp);font-variation-settings:'wdth' 88,'opsz' 60;
  font-weight:800;font-size:2.75rem;line-height:1;letter-spacing:-.03em;color:var(--ice);
}
.revs-stars svg{width:19px;height:19px}
.revs-count{font-size:0.90625rem;font-weight:700;color:var(--mist)}

.revs-bars{list-style:none;margin:0;padding:0;display:grid;gap:6px}
.revs-bars li{display:grid;grid-template-columns:14px 1fr 34px;gap:9px;align-items:center}
.rb-n{font-size:0.8125rem;font-weight:700;color:var(--mist);text-align:right}
.rb-track{height:7px;border-radius:99px;background:rgba(234,244,238,.13);overflow:hidden}
.rb-track i{display:block;height:100%;background:var(--gold);border-radius:99px}
.rb-c{font-size:0.8125rem;color:var(--mist);text-align:right;font-variant-numeric:tabular-nums}

.revs-list{list-style:none;margin:18px 0 0;padding:0;display:grid;gap:12px}
.rev{
  padding:16px 17px;
  background:var(--glass);border:1px solid var(--glass-line);border-radius:var(--r-card);
}
.rev-top{display:flex;align-items:center;justify-content:space-between;gap:12px}
.rev-top .stars svg{width:15px;height:15px}
.rev-date{font-size:0.8125rem;color:var(--mist);flex:0 0 auto}
.rev-title{
  display:block;margin-top:10px;
  font-size:1.03125rem;font-weight:800;line-height:1.3;color:var(--ice);
}
.rev-body{margin:7px 0 0;font-size:0.96875rem;line-height:1.5;color:var(--mist)}
.rev-by{margin:11px 0 0;display:flex;align-items:center;gap:9px;flex-wrap:wrap}
.rev-name{font-size:0.90625rem;font-weight:700;color:var(--ice)}
.rev-ok{
  font-size:0.75rem;font-weight:800;letter-spacing:.02em;color:var(--gold);
  border:1px solid rgba(245,193,54,.4);border-radius:var(--r-pill);padding:2px 9px;
}
html[lang="zh-Hans"] .revs-eye,html[lang="zh-Hant"] .revs-eye{letter-spacing:.06em}

.revs-more{
  display:block;width:100%;margin-top:14px;cursor:pointer;
  padding:16px 18px;border-radius:var(--r-pill);
  background:transparent;border:1.5px solid rgba(245,193,54,.45);
  color:var(--gold);font-family:var(--ui);font-size:1rem;font-weight:800;
}
@media (prefers-reduced-motion:no-preference){
  .revs-more{transition:border-color .16s ease,background-color .16s ease}
}
.revs-more:hover{border-color:var(--gold);background-color:rgba(245,193,54,.09)}
.revs-more:focus-visible{outline:2px solid var(--gold);outline-offset:3px}
.revs-more[disabled]{opacity:.55;cursor:default}

/* ---------- review photos ---------- */
.rev-shots{
  list-style:none;margin:12px 0 0;padding:0;
  display:flex;gap:8px;flex-wrap:wrap;
}
.rev-shot{
  display:block;padding:0;cursor:zoom-in;
  width:74px;height:74px;border-radius:12px;overflow:hidden;
  background:var(--jade);border:1px solid var(--glass-line);
}
.rev-shot img{width:100%;height:100%;object-fit:cover;display:block}
@media (prefers-reduced-motion:no-preference){
  .rev-shot{transition:border-color .16s ease}
}
.rev-shot:hover{border-color:rgba(245,193,54,.55)}
.rev-shot:focus-visible{outline:2px solid var(--gold);outline-offset:3px}

/* Full size. hidden does the hiding, so the viewer is inert to a screen
   reader when closed without needing anything remembered in JavaScript. */
.rev-lb[hidden]{display:none}
.rev-lb{
  position:fixed;inset:0;z-index:130;
  /* svh, not the implicit 100% of inset:0: on a phone the browser chrome
     changes the viewport height as it hides, and the small-viewport unit is
     the one that stays put. Without it the overlay is centred against a box
     that resizes under it while the shopper is looking at the photograph. */
  height:100svh;
  display:grid;place-items:center;padding:22px;
  background:rgba(7,42,29,.94);cursor:zoom-out;
}
@supports (backdrop-filter:blur(6px)){
  .rev-lb{background:rgba(7,42,29,.86);backdrop-filter:blur(6px)}
}
.rev-lb img{
  max-width:100%;max-height:100%;
  border-radius:var(--r-card);display:block;cursor:default;
}
.rev-lb-x{
  position:absolute;top:14px;right:14px;cursor:pointer;
  width:44px;height:44px;display:grid;place-items:center;padding:0;
  background:var(--glass);border:1.5px solid var(--glass-line);
  border-radius:var(--r-pill);color:var(--ice);
}
.rev-lb-x svg{width:19px;height:19px;display:block}
.rev-lb-x:focus-visible{outline:2px solid var(--gold);outline-offset:3px}

/* ---------- header language chip ---------- */
/* Sized and stripped to sit with the bare cart and burger rather than beside
   them as a third, louder control. */
.bar .bar-lang{
  height:44px;padding:0 22px 0 9px;
  background-color:transparent;border:0;
  background-position:right 6px center;
  color:var(--ice);font-family:var(--ui);font-size:0.90625rem;font-weight:800;
  letter-spacing:.02em;cursor:pointer;flex:0 0 auto;
}
.bar .bar-lang:hover{background-color:rgba(245,193,54,.12)}
.bar .bar-lang{border-radius:var(--r-pill)}
.bar .bar-lang option{color:#12291D;background:#FDF5E4}
@media (max-width:359px){
  .bar .bar-lang{padding:0 19px 0 5px;font-size:0.84375rem;background-position:right 4px center}
}

/* ============================================================
   DESKTOP

   The page was drawn as a 480px column and stays one on a phone. Past 900px
   that column is not "mobile-friendly on desktop", it is a third of the screen
   with two empty thirds beside it — so the fold splits: the fruit on the left
   where the eye lands, the decision on the right where it stays put while the
   photographs scroll.

   Everything here is additive. Below 900px not one rule applies, so the phone
   layout that the rest of this file describes is untouched.
   ============================================================ */

/* Inert until the breakpoint: with display:contents the two wrappers are not
   boxes at all, so margins collapse exactly as they did before they existed. */
.fold,.fold-media,.fold-buy{display:contents}
/* The masthead is a real box, not flattened: it needs the phone's side gutter
   the way .shot and .head do, since .fold gives it nothing. */
/* The top gutter is the masthead's own, because .fold is display:contents on a
   phone and cannot hold one. Without it the H1 started immediately under the
   sticky header, with the announcement strip's rule as the only thing between
   two blocks of type. */
.fold-head{display:block;padding:16px 20px 0;margin:0 0 14px}

@media (min-width:900px){
  .page{max-width:1180px}

  /* The header keeps the phone's 16px gutter unless told otherwise, which puts
     the wordmark 18px inboard of the fruit below it. One gutter for the page. */
  .strip,.bar{padding-left:34px;padding-right:34px}
  .bar .mark b{font-size:1.4375rem}
  .mark-tag{font-size:0.78125rem}

  .fold{
    display:grid;
    grid-template-columns:minmax(0,1.06fr) minmax(0,1fr);
    column-gap:52px;
    align-items:start;
    padding:0 34px;
    /* Wider here than on a phone: the desktop header is taller and the title
       is a third bigger, so the same 16px would read as a tighter gap. */
    margin-top:34px;
  }
  .fold-media,.fold-buy{display:block;min-width:0}
  /* Full width above both columns, so the gallery and the buy panel still sit
     side by side underneath it. Not sticky — the masthead scrolls away; the
     gallery below it is the thing that holds. */
  .fold-head{grid-column:1 / -1;padding:0;margin:0 0 22px}

  /* The gallery holds still while the buy column scrolls past it, then the buy
     column holds still once its own content runs out — whichever is shorter
     sticks. Both need a top offset clear of the sticky header. */
  .fold-media{position:sticky;top:150px}

  /* These carried the phone's side gutters; the grid owns spacing now. */
  .shot{margin:0;border-radius:var(--r-card)}
  .thumbs{padding:10px 0 5px}
  /* .head is two different things: the PDP masthead (inside the fold grid,
     which already supplies the gutter) and the content wrapper the shell uses
     for policy/FAQ/contact pages (which supplies its own). Scope, or the
     standalone pages lose their left margin. */
  .fold-buy .head{padding:0}
  .head{padding-left:34px;padding-right:34px}
  .spec{margin-left:0;margin-right:0}
  .buy-wrap{padding:0}
  .buy{padding:26px 0 0}
  .buy .ask{margin-left:0;margin-right:0}

  h1{font-size:2.75rem}
  .lede{font-size:1.125rem}

  /* ---- below the fold: the bands get a measure, not the whole screen ---- */
  .how-wrap,.taste-wrap,.faq,.revs-wrap{margin-left:auto;margin-right:auto}
  .how,.taste{padding-left:34px;padding-right:34px}
  .faq{padding-left:34px;padding-right:34px;max-width:820px;margin-inline:auto}
  .revs-wrap{padding:0 34px}

  /* Four steps read as four steps when they are on one line. */
  .steps{grid-template-columns:repeat(4,1fr)}

  /* Reviews are short and many — one long column wastes the width. */
  .revs-list{grid-template-columns:1fr 1fr;align-items:start}
  .revs-more{max-width:340px;margin-left:auto;margin-right:auto}

  .foot{padding-left:34px;padding-right:34px}
}

/* Past this the gutters stop growing and the page just centres. */
@media (min-width:1240px){
  .fold{column-gap:64px}
}

/* ---------- policy pages ---------- */
/* The body is rich text from Settings → Policies, so the shape of it is not
   ours to choose — every element it can emit needs a rule, or the page falls
   back to browser defaults halfway down and stops looking like the store. */
.shopify-policy__body .rte{
  /* ch is unreliable here — it measures the fallback face until Plus Jakarta
     loads, which let the measure out to ~95 characters. A px ceiling keeps the
     line length honest whatever is rendering. */
  margin:20px 0 0;max-width:min(70ch,720px);
  font-size:1.03125rem;line-height:1.65;color:var(--mist);
}
.shopify-policy__body .rte > *:first-child{margin-top:0}
.shopify-policy__body .rte h1,.shopify-policy__body .rte h2,.shopify-policy__body .rte h3,.shopify-policy__body .rte h4,.shopify-policy__body .rte strong,.shopify-policy__body .rte b{
  color:var(--ice);
}
.shopify-policy__body .rte h1,.shopify-policy__body .rte h2{
  font-family:var(--dsp);font-variation-settings:'wdth' 90,'opsz' 40;
  font-weight:800;font-size:1.4375rem;line-height:1.25;letter-spacing:-.02em;
  margin:30px 0 10px;
}
.shopify-policy__body .rte h3,.shopify-policy__body .rte h4{font-size:1.125rem;font-weight:800;margin:24px 0 8px;line-height:1.3}
.shopify-policy__body .rte p{margin:0 0 14px}
.shopify-policy__body .rte ul,.shopify-policy__body .rte ol{margin:0 0 14px;padding-left:22px}
.shopify-policy__body .rte li{margin:0 0 7px}
.shopify-policy__body .rte a{color:var(--gold);text-underline-offset:2px}
.shopify-policy__body .rte hr{border:0;border-top:1px solid var(--glass-line);margin:26px 0}
.shopify-policy__body .rte table{width:100%;border-collapse:collapse;margin:0 0 16px;display:block;overflow-x:auto}
.shopify-policy__body .rte th,.shopify-policy__body .rte td{
  border:1px solid var(--glass-line);padding:9px 11px;text-align:left;font-size:0.96875rem;
}
.shopify-policy__body .rte th{color:var(--ice);font-weight:800}
html[lang="zh-Hans"] .shopify-policy__body .rte,html[lang="zh-Hant"] .shopify-policy__body .rte{font-family:var(--cjk);line-height:1.8}
@media (min-width:900px){
  .shopify-policy__body .rte{font-size:1.0625rem}
  .shopify-policy__body .rte h1,.shopify-policy__body .rte h2{font-size:1.625rem}
}

/* The gallery gained a sixth image (the nutrition card), so the thumbnail rail
   divides by six. The rail already scrolls, but six-across keeps every slide
   reachable without one. */
.thumbs figure{flex:0 0 calc((100% - 5 * var(--g)) / 6)}

/* ---------- shop policies (/policies/*) ---------- */
/* Shopify emits this markup itself — .shopify-policy__container / __title /
   __body > .rte — so these are the only hooks available. Without them the page
   falls back to browser defaults: Times, black on green, edge to edge. */
.shopify-policy__container{max-width:none;padding:0}
.shopify-policy__title{margin:0 0 6px}
.shopify-policy__title h1{
  font-family:var(--dsp);font-variation-settings:'wdth' 90,'opsz' 60;
  font-weight:800;font-size:2.375rem;line-height:1.1;letter-spacing:-.02em;color:var(--ice);
  margin:0;
}
.shopify-policy__body{margin:0}
@media (min-width:900px){
  .shopify-policy__title h1{font-size:3.25rem}
}

/* ---------- cart drawer: quantity and removal ---------- */
/* Right column: price, then quantity, then the way out. Right-aligned so the
   three read as one stack rather than three loose controls. */
/* The image plus a fixed right column leaves the middle narrow, and the box
   select has to survive Vietnamese in it — "4 trái sầu riêng" is the longest
   label in the theme. Smaller type buys it the room. */
/* The count, shown rather than adjustable. */
.line-del{
  padding:0;cursor:pointer;background:none;border:0;
  font-family:var(--ui);font-size:0.84375rem;font-weight:700;color:var(--mist);
  text-decoration:underline;text-underline-offset:3px;
}
.line-del:hover{color:var(--gold)}
.line-del:focus-visible{outline:2px solid var(--gold);outline-offset:3px;border-radius:4px}
html[lang="zh-Hans"] .line-del,html[lang="zh-Hant"] .line-del{font-family:var(--cjk)}

/* ---------- buy-panel info panels ---------- */
/* Closed by default and quiet when closed: this sits under the pay icons, at
   the very bottom of the fold, and its job is to be available rather than to
   compete with the button above it. */
.binfo{margin:18px 0 0;border-top:1px solid var(--glass-line)}
.binfo details{border-bottom:1px solid var(--glass-line)}
.binfo summary{
  display:flex;align-items:center;gap:11px;cursor:pointer;list-style:none;
  padding:15px 2px;
  font-family:var(--ui);font-size:1rem;font-weight:800;color:var(--ice);
  position:relative;
}
.binfo summary::-webkit-details-marker{display:none}
.binfo-i{width:19px;height:19px;flex:0 0 auto;color:var(--gold)}
.binfo summary::after{
  content:"";position:absolute;right:6px;top:50%;
  width:9px;height:9px;margin-top:-6px;
  border-right:2px solid var(--gold);border-bottom:2px solid var(--gold);
  transform:rotate(45deg);transform-origin:center;
}
@media (prefers-reduced-motion:no-preference){
  .binfo summary::after{transition:transform .18s ease}
}
.binfo details[open] summary::after{transform:rotate(-135deg);margin-top:-2px}
.binfo summary:focus-visible{outline:2px solid var(--gold);outline-offset:-2px;border-radius:10px}
.binfo-a{
  margin:0;padding:0 2px 16px 30px;
  font-size:0.96875rem;line-height:1.6;color:var(--mist);
}
/* The bullet form of the same panel. Same left inset as .binfo-a so an open
   panel lines up with a closed one, and the marker is drawn rather than a list
   bullet: a real disc sits on the text baseline and looks like a typo next to
   the gold ticks used everywhere else on this page.

   Sized a little larger than the prose it replaced — these are the lines a
   shopper actually reads before paying, and the audience skews older. */
.binfo-list{
  margin:0;padding:0 2px 16px 30px;list-style:none;
  display:flex;flex-direction:column;gap:9px;
}
.binfo-list li{
  position:relative;padding-left:17px;
  font-size:0.96875rem;line-height:1.55;color:var(--mist);
}
.binfo-list li::before{
  content:"";position:absolute;left:0;top:.62em;
  width:6px;height:6px;border-radius:50%;
  background:var(--gold);
}
html[lang="zh-Hans"] .binfo-list,html[lang="zh-Hant"] .binfo-list{font-family:var(--cjk)}
html[lang="zh-Hans"] .binfo-list li,html[lang="zh-Hant"] .binfo-list li{line-height:1.75}
html[lang="zh-Hans"] .binfo summary,html[lang="zh-Hant"] .binfo summary,
html[lang="zh-Hans"] .binfo-a,html[lang="zh-Hant"] .binfo-a{font-family:var(--cjk)}
html[lang="zh-Hans"] .binfo-a,html[lang="zh-Hant"] .binfo-a{line-height:1.75}

/* ---------- Zelle ---------- */
/* Six marks now, not five. The columns stay fractional with a 46px ceiling so
   the row still fits a 320px screen — six fixed 46s plus gaps would overflow. */
.pay{grid-template-columns:repeat(6,minmax(0,1fr))}
.pay .pay-zelle{
  /* contain, not cover: the wordmark must not be cropped. The letterboxing
     that leaves is filled by matching the SVG's own field colour, so the tile
     reads as solid purple instead of a logo floating on white. */
  object-fit:contain;background:#6C1CD3;
}

/* ---------- wholesale ---------- */
.whl-grid{
  list-style:none;margin:24px 0 0;padding:0;
  display:grid;gap:12px;
}
.whl-grid li{
  padding:18px 18px 19px;
  background:var(--glass);border:1px solid var(--glass-line);border-radius:var(--r-card);
}
.whl-i{width:22px;height:22px;display:block;color:var(--gold);margin-bottom:11px}
.whl-grid b{display:block;font-size:1.0625rem;font-weight:800;color:var(--ice);line-height:1.3}
.whl-grid p{margin:7px 0 0;font-size:0.96875rem;line-height:1.55;color:var(--mist)}
html[lang="zh-Hans"] .whl-grid p,html[lang="zh-Hant"] .whl-grid p{line-height:1.75}
@media (min-width:640px){
  .whl-grid{grid-template-columns:1fr 1fr}
}
.binfo-link{
  display:inline-flex;align-items:center;min-height:44px;
  margin:0 0 9px 30px;
  font-family:var(--ui);font-size:0.9375rem;font-weight:800;color:var(--gold);
  text-underline-offset:3px;
}
.binfo-link:focus-visible{outline:2px solid var(--gold);outline-offset:3px;border-radius:4px}

/* The wholesale buy block reuses .tier, so it inherits the product page's
   card, radio, selected-state and saving badge for free. It only needs its
   own outer spacing — it is not sitting in the product fold's grid. */
.whl-buy{padding:0;margin:26px 0 0}
/* The product page's .ask sets the heading and its note side by side, which
   works for "Choose your box · WHOLE FRUIT". "Choose your case · TRADE PRICING,
   NO MINIMUM TERM" is twice the length and drove the heading to three lines,
   so here they stack. */
.whl-buy .ask{display:block;margin:0 0 16px}
.whl-buy .ask h2{margin:0}
.whl-buy .ask .hint{margin:7px 0 0;text-align:left}
.whl-buy .cta{margin-top:18px}
.whl-buy + .whl-grid{margin-top:30px}

/* ---------- rating: durians, not stars ---------- */
/* The glyph is taller than it is wide, so height drives the size and the width
   follows from the viewBox. Fixed square sizing left a third of each slot
   empty and shrank the fruit to the point where the spikes turned to fuzz. */
/* The 0.754 aspect that used to live here belonged to a durian glyph, back
   when the rating was drawn with fruit rather than stars. The glyph is a
   square 20x20 star now, and three later rules already set square sizes, so
   these were overridden and doing nothing — but a rule that says "0.754 is the
   glyph's own ratio" next to a glyph whose ratio is 1 is a trap for whoever
   edits this next. Removed rather than corrected: the sizes below own it. */
/* The gaps are wider than a star row needs, because these read as objects
   rather than as a single continuous rule of ink. */
.stars .s-bg,.stars .s-fg{gap:4px}

/* ---------- room for the dock, in the footer's own colour ---------- */
/* Only where a dock exists: it is rendered by the product section, so the
   cart, policy and wholesale pages have none and would otherwise carry a
   hundred pixels of dead space for a bar that is not there. */
body:has(.dock) .foot{
  padding-bottom:calc(96px + env(safe-area-inset-bottom, 0px));
}

/* ---------- FAQ page: grouped ---------- */
/* Twenty-seven questions in one undifferentiated stack is a wall. The group
   headings are what let someone scan for their own question rather than read
   the lot. */
.faq-group{
  margin:34px 0 12px;
  font-size:1.375rem;line-height:1.2;letter-spacing:-.02em;color:var(--gold);
}
.faq-group:first-of-type{margin-top:24px}
.faq-page{padding-left:0;padding-right:0}
@media (min-width:900px){
  .faq-group{font-size:1.625rem;margin-top:44px}
}

/* ---------- rating jumps to the reviews ---------- */
/* The reviews link was 24px tall — the smallest target on the page, and the
   first thing a careful buyer taps. 44px is the recommended minimum for a
   fingertip; the padding is negative-margined back out so raising the target
   does not push the rating row down the page. */
.r-link{
  display:inline-flex;align-items:center;gap:9px;
  min-height:44px;padding:10px 6px;margin:-10px -6px;
  color:inherit;text-decoration:none;border-radius:8px;
}
.r-link .r-count{text-decoration:underline;text-decoration-color:rgba(173,200,184,.4);text-underline-offset:3px}
@media (prefers-reduced-motion:no-preference){
  .r-link .r-count{transition:text-decoration-color .16s ease,color .16s ease}
}
.r-link:hover .r-count{color:var(--ice);text-decoration-color:var(--gold)}
.r-link:focus-visible{outline:2px solid var(--gold);outline-offset:3px}
/* Land the heading below the sticky header rather than under it. */
#reviews{scroll-margin-top:156px}

/* ============================================================
   Buy box F — per-fruit ladder.
   Everything from here down replaces the two-row tier card with
   a three-row one whose largest number is the price of a single
   fruit. Nothing above this line was removed; the rules that
   styled .t-top / .t-bottom simply have no markup to match any
   more, and the ones that still apply (.tier, .t-rec, .t-qty,
   .t-oos, .t-fruit-row) are inherited rather than restated.
   ============================================================ */

/* The stack is ordered by each card's own CSS order, not by source order.
   That is what lets the revealed tiers slot back into the ladder in numeric
   order instead of piling up at the bottom, and it is the same mechanism the
   desktop grid uses. */
.buy .tiers{display:flex;flex-direction:column;gap:10px}
.buy .tier{
  display:flex;flex-direction:column;align-items:stretch;gap:0;
  min-height:0;margin-bottom:0;padding:14px 15px 12px;
}
.buy .tier input{width:20px;height:20px}
.buy .tier input:checked::after{width:10px;height:10px}

.t-r1{display:flex;align-items:center;gap:11px;min-width:0}
.t-r1 .t-qty{
  display:block;font-family:var(--ui);font-size:1.03125rem;font-weight:800;
  line-height:1.2;letter-spacing:-.02em;color:var(--ice);min-width:0;
  font-variation-settings:normal;
}
.tier.on .t-r1 .t-qty{color:var(--gold)}
.t-was{
  margin-left:auto;flex:0 0 auto;white-space:nowrap;
  font-size:0.8125rem;font-weight:500;color:var(--mist);
  text-decoration:line-through;text-decoration-thickness:1.5px;
}
.t-r1 .t-oos{margin-left:auto;flex:0 0 auto;font-size:0.75rem;font-weight:700;color:var(--mist)}

/* Row two: the unit price, and the total beside it. The total is never
   smaller than a size step down from the unit price and never leaves the
   card — the button carries it too. */
.t-unit{
  font-family:var(--dsp);font-variation-settings:'wdth' 92,'opsz' 40;
  font-size:2.125rem;font-weight:800;letter-spacing:-.04em;line-height:1;
  color:var(--ice);font-variant-numeric:tabular-nums;white-space:nowrap;
}
.tier.on .t-unit{color:var(--gold)}
.t-pre,.t-post{font-size:0.84375rem;font-weight:700;color:var(--mist);letter-spacing:-.01em;white-space:nowrap}
.t-pre:empty,.t-post:empty{display:none}
.t-pre{order:-1}
html[lang^="zh"] .t-pre,html[lang^="zh"] .t-post{letter-spacing:0}
.t-tot{
  margin-left:auto;flex:0 0 auto;white-space:nowrap;
  font-size:0.84375rem;font-weight:700;color:var(--mist);font-variant-numeric:tabular-nums;
}
.tier.on .t-tot{color:var(--ice)}

/* Row three: the fruit, the weight, and what this one cost. The durians moved
   inline — as their own row they were 54px of decoration on every card. */
.t-r3{display:flex;align-items:center;gap:9px;margin-top:9px;padding-left:30px;min-width:0}
.t-r3 .t-fruit-row{display:flex;gap:1.5px;flex:0 0 auto}
.t-r3 .t-fruit-row img{width:14px;height:20px;object-fit:contain;display:block}
.t-marg{
  margin-left:auto;flex:0 0 auto;white-space:nowrap;
  font-size:0.71875rem;font-weight:700;color:var(--gold);
  background:rgba(245,193,54,.13);border-radius:5px;padding:2px 7px;
}
.tier.oos .t-unit,.tier.oos .t-r1 .t-qty{color:var(--mist)}

/* Percentage top-right; the dollar saving is implied by the strikethrough
   beside the price, where the eye already is. One idea per corner. */
.t-pct{
  position:absolute;top:-9px;right:12px;z-index:2;
  padding:2.5px 8px;border-radius:6px;
  font-family:var(--ui);font-size:0.6875rem;font-weight:800;letter-spacing:.01em;
  background:var(--abyss);color:var(--gold);border:1px solid var(--gold);
  font-variant-numeric:tabular-nums;
}

/* ---------- more box sizes ---------- */
.t-extra{display:none}
.t-extra.on{display:contents}
.t-more{
  width:100%;margin-top:11px;padding:8px;cursor:pointer;
  background:none;border:0;
  font-family:var(--ui);font-size:0.84375rem;font-weight:600;color:var(--mist);
  text-decoration:underline;text-decoration-color:rgba(169,195,181,.4);text-underline-offset:4px;
}
.t-more:hover{color:var(--ice)}
.t-more:focus-visible{outline:2px solid var(--gold);outline-offset:2px;border-radius:8px}

/* ---------- express checkout ---------- */
/* Gold Add first, Shopify's own buttons under it. Sized, not restyled — the
   brand marks are the ones a shopper recognises and Shopify draws them. */
.dg-express{margin-top:10px}
.dg-express .shopify-payment-button__button{
  border-radius:var(--r-pill);min-height:54px;font-family:var(--ui);font-size:1rem;font-weight:700;
}
.dg-express .shopify-payment-button__more-options{
  margin-top:8px;font-family:var(--ui);font-size:0.78125rem;font-weight:600;color:var(--mist);
  text-underline-offset:3px;
}
.dg-express .shopify-payment-button__more-options:hover{color:var(--ice)}

/* ---------- the three answers, at the moment of the decision ---------- */
.assure{
  margin-top:14px;padding:17px 18px;border-radius:20px;
  background:rgba(255,255,255,.03);border:1px solid var(--glass-line);
  display:flex;flex-direction:column;gap:17px;
}
.assure .as{
  display:flex;align-items:flex-start;gap:14px;margin:0;
  font-family:var(--ui);font-size:0.96875rem;line-height:1.55;color:var(--mist);
}
/* A ring drawn in CSS rather than baked into each symbol, so one rule sets the
   size and weight of every disc in the block and the sprite keeps holding
   glyphs. flex:0 0 auto and the explicit height stop it being squashed into an
   oval by a long line of text beside it. */
.assure .as-ic{
  flex:0 0 auto;width:40px;height:40px;border-radius:50%;
  border:1.5px solid rgba(255,201,77,.5);
  display:flex;align-items:center;justify-content:center;
  color:var(--gold);
}
.assure .as-ic svg{width:20px;height:20px;fill:none;stroke:currentColor}
.assure .as-tx{min-width:0}
.assure .as b{color:var(--ice);font-weight:700}
/* The cut-off time. Gold because it is the one figure in the sentence the
   shopper is deciding against — "can I still make today's flight".

   Written as b.as-hi, and the element has to be in the selector: the rule above
   is .assure .as b, which carries an element on top of its two classes and so
   outranks a bare two-class selector however far down the file it sits. Left as
   .assure .as-hi the time rendered in ice like every other bold run in the
   block, and the one word meant to be gold was the one word that was not. */
.assure .as b.as-hi{color:var(--gold);font-weight:800}

/* ---------- sticky bar ---------- */
/* Hidden until the buying options have scrolled past. Slides rather than
   appears, so it reads as arriving on cue instead of blinking into existence. */
.dock{transform:translateY(110%);pointer-events:none}
.dock.on{transform:none;pointer-events:auto}
.dock[hidden]{display:none}
@media (prefers-reduced-motion:no-preference){
  .dock{transition:transform .3s cubic-bezier(.2,.75,.25,1)}
}
.dock .d-l{flex:1 1 auto;min-width:0;display:block;margin:0}
/* The select's label, for screen readers only.

   The markup has always carried .dg-vh on it and the stylesheet never defined
   the class, so "Choose your box" rendered as a visible line above the select —
   which is what threw the bar out of alignment: the label and the select
   stacked in the left column while the button stayed centred against both.

   Not display:none, which would take it away from screen readers too, and not
   an empty label, which would leave the select unnamed. Clipped to nothing and
   left in the accessibility tree, which is what the class was written for. */
.dg-vh{
  position:absolute;width:1px;height:1px;margin:-1px;padding:0;border:0;
  overflow:hidden;white-space:nowrap;clip:rect(0 0 0 0);clip-path:inset(50%);
}
.dock .d-sel{
  width:100%;min-height:50px;cursor:pointer;
  font-family:var(--ui);font-size:1.03125rem;font-weight:700;color:var(--ice);
  background:var(--jade) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='13' height='8'%3E%3Cpath d='M1.5 1.5l5 5 5-5' stroke='%23F5C136' stroke-width='2' fill='none' stroke-linecap='round'/%3E%3C/svg%3E") no-repeat right 15px center;
  border:1.5px solid var(--glass-line);border-radius:var(--r-pill);
  padding:12px 40px 12px 18px;appearance:none;-webkit-appearance:none;
  text-overflow:ellipsis;
}
.dock .d-sel option{color:#12291D;background:#F2EEE2;font-weight:600}
.dock .d-sel:focus-visible{outline:3px solid var(--gold);outline-offset:3px}
html[lang="zh-Hans"] .dock .d-sel,html[lang="zh-Hant"] .dock .d-sel{font-family:var(--cjk),var(--ui)}
.dock #dbtn{
  flex:0 0 auto;border:0;cursor:pointer;background:var(--gold);color:var(--abyss);
  min-height:50px;padding:12px 20px;border-radius:var(--r-pill);
  font-family:var(--ui);font-weight:800;font-size:1.03125rem;letter-spacing:-.01em;white-space:nowrap;
}
html[lang="zh-Hans"] .dock #dbtn,html[lang="zh-Hant"] .dock #dbtn{font-family:var(--cjk),var(--ui)}
.dock #dbtn:focus-visible{outline:3px solid var(--ice);outline-offset:3px}

@media (max-width:359px){
  .t-unit{font-size:1.875rem}
  .d-p{font-size:1.125rem}
  .dock button{padding:14px 18px;font-size:0.9375rem}
}

/* ---------- desktop: the ladder becomes a two-column grid ---------- */
/* Two columns, not three. The card is a bigger object than it looks — a 34px
   price and a fruit row — and at three columns in a ~520px buy column it
   clips its own name and weight in every language. */
@media (min-width:900px){
  .buy .tiers{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}
  /* The reveal is a button at every width — a desktop that silently shows
     all six makes the button on a phone look like a different product. */
  .buy .t-more{display:none}
  .t-r3{padding-left:0;flex-wrap:wrap;row-gap:4px}
  .t-r3{row-gap:7px}
  .t-marg{margin-left:0}
  .t-unit{font-size:1.9375rem}
  .buy .cta,.buy .dg-express{max-width:none}
}

/* ============================================================
   Cart drawer.
   Proof, then the box, then what the box saves, then the money,
   then one gold button. A card only where a card means something
   — the item you bought, the saving you have — and hairlines
   between everything else, so nothing competes with the button.
   ============================================================ */

.drawer{--rule:rgba(244,249,246,.15);--card:rgba(255,255,255,.045)}
.dr-head{padding:clamp(4px,1.1svh,11px) 18px clamp(3px,.9svh,8px);gap:12px;
  border-bottom:1px solid var(--rule)}
.dr-head h2{font-family:var(--dsp);font-variation-settings:'wdth' 92,'opsz' 40;
  font-size:clamp(1.3125rem,3.6svh,1.75rem);font-weight:800;letter-spacing:-.035em;line-height:1}
html[lang^="zh"] .dr-head h2{font-family:var(--cjk),var(--dsp);letter-spacing:0;
  font-size:clamp(1.25rem,3.3svh,1.625rem)}
.dr-x{width:clamp(38px,5.6svh,46px);height:clamp(38px,5.6svh,46px);
  font-size:clamp(1.3125rem,3.3svh,1.5625rem);border:1.5px solid var(--glass-line);background:none}
.dr-body{padding:0 18px 6px}

/* ---------- proof, before anything is asked for ----------
   The two numbers a first-time buyer of a $240 fruit actually wants: how
   many other people did this, and what they said afterwards. Gold on the
   count because it is the one number that cannot be argued with. */
/* The rating marks. The lit star carries its own gradient, so it cannot take
   a colour from CSS — the empty row underneath is a separate flat symbol and
   that is the one currentColor tints. */
.stars .s-bg svg{color:var(--mist);opacity:.3;fill:currentColor;filter:none}
.stars .s-fg svg{fill:none}

/* The rating marks were still carrying the durian's portrait proportions —
   13.6 x 18 on a symbol that is square, which stretched every star. Square,
   bigger, and set tight: a rating reads as one object, not five. */
.stars svg,.revs-stars svg,.rev-top .stars svg{width:21px;height:21px}
.revs-stars svg{width:26px;height:26px}
.rev-top .stars svg{width:17px;height:17px}
.stars .s-bg,.stars .s-fg{gap:1.5px}

/* The luster: a hairline of shadow to lift the star off the green. A warm
   bloom used to sit under it too, but five overlapping glows stopped reading
   as shine and started reading as a lit rectangle behind the row. */
.stars .s-fg svg{filter:drop-shadow(0 1px 0 rgba(0,0,0,.4))}

/* -------------------------------------------------------------- benefits --
   Mobile first, because that is where it is read: photo, then the claim, then
   the numbers as three tiers of decreasing size — the calorie line, the four
   daily-value chips, the four cards. Two columns only once there is room for
   the photo to sit beside the copy rather than shrink it. */
.benefits{padding:34px 0 8px}
.bn-in{max-width:1180px;margin:0 auto;padding:0 16px;display:grid;gap:22px}
.bn-shot{margin:0;border-radius:22px;overflow:hidden;background:var(--jade);
  border:1px solid var(--rule)}
.bn-shot img{display:block;width:100%;height:auto;aspect-ratio:1;object-fit:cover}

.bn-eye{
  margin:0;font-family:var(--ui);font-size:0.75rem;font-weight:800;
  letter-spacing:.2em;text-transform:uppercase;color:var(--gold);
}
.bn-h{
  margin:11px 0 0;font-family:var(--dsp);font-variation-settings:'wdth' 94,'opsz' 60;
  font-size:clamp(1.875rem,7.4vw,2.875rem);font-weight:800;letter-spacing:-.04em;
  line-height:1.02;color:var(--ice);text-wrap:balance;
}
.bn-h i{font-style:normal;color:var(--gold)}
html[lang^="zh"] .bn-h{font-family:var(--cjk),var(--dsp);letter-spacing:0;line-height:1.2}
.bn-sub{
  margin:13px 0 0;max-width:56ch;font-family:var(--ui);
  font-size:clamp(0.9375rem,4vw,1.125rem);font-weight:500;line-height:1.5;color:var(--mist);
}

/* ---------------------------------------------- the nutrition panel -------
   A Nutrition Facts label, because it is a format shoppers have read a
   thousand times and do not have to be taught. Ink on white, not the page's
   green: the panel's whole authority — and its legibility, which matters most
   for the readers this shop actually has — comes from that contrast, so it
   sits on the section as a white document rather than dissolving into it.

   Three rule weights do the grouping, exactly as the real panel does it:
   hairline separates rows, 4px separates a heading from its rows, 9px
   separates whole sections. Nothing here is decorative; each weight means a
   different size of break. */
.nfp{
  margin:20px 0 0;padding:12px 14px 11px;
  background:#fff;color:#0B0B0B;
  border:1px solid #0B0B0B;border-radius:12px;
  font-family:var(--ui);font-variant-numeric:tabular-nums;
  max-width:420px;
}
html[lang^="zh"] .nfp{font-family:var(--cjk),var(--ui)}

.nfp-t{
  margin:0;font-family:var(--dsp);font-variation-settings:'wdth' 82,'opsz' 60;
  font-size:clamp(1.875rem,8.2vw,2.375rem);font-weight:800;letter-spacing:-.035em;
  line-height:1.02;color:#0B0B0B;
}
html[lang^="zh"] .nfp-t{font-family:var(--cjk),var(--dsp);letter-spacing:0;font-size:clamp(1.625rem,7vw,2rem)}

.nfp-serv{
  display:flex;justify-content:space-between;align-items:baseline;gap:12px;
  margin:5px 0 0;padding-top:5px;border-top:1px solid #0B0B0B;
  font-size:0.875rem;font-weight:600;
}
.nfp-serv b{font-weight:800}

/* The calorie block: the one figure most people actually look for. */
.nfp-cal{margin:0;padding:3px 0 2px;border-top:9px solid #0B0B0B}
.nfp-amt{display:block;font-size:0.75rem;font-weight:700}
.nfp-calrow{display:flex;justify-content:space-between;align-items:flex-end;gap:12px}
.nfp-calrow b{
  font-family:var(--dsp);font-variation-settings:'wdth' 88,'opsz' 60;
  font-size:clamp(1.5625rem,6.6vw,1.875rem);font-weight:800;letter-spacing:-.03em;line-height:1.06;
}
html[lang^="zh"] .nfp-calrow b{font-family:var(--cjk),var(--dsp);letter-spacing:0}
.nfp-caln{font-size:clamp(1.9375rem,8.4vw,2.375rem) !important}

.nfp-dv{
  margin:0;padding:2px 0;border-top:4px solid #0B0B0B;
  text-align:right;font-size:0.78125rem;font-weight:800;
}

.nfp-rows{list-style:none;margin:0;padding:0}
.nfp-rows li{
  display:flex;justify-content:space-between;align-items:baseline;gap:12px;
  padding:4px 0;border-top:1px solid #0B0B0B;
  font-size:0.875rem;font-weight:500;line-height:1.35;
}
.nfp-rows li b{font-weight:800}
.nfp-rows li i{font-style:normal;font-weight:800;flex:0 0 auto}
/* Sub-nutrients sit under their parent, the way fibre sits under carbohydrate. */
.nfp-rows li.sub{padding-left:17px}
.nfp-vits{border-top:9px solid #0B0B0B;margin-top:0}
.nfp-vits li:first-child{border-top:0}

.nfp-foot{
  margin:0;padding-top:5px;border-top:4px solid #0B0B0B;
  font-size:0.71875rem;font-weight:500;line-height:1.35;
}

/* Small phones: the panel keeps its structure and gives up only air. */
@media (max-width:359px){
  .nfp{padding:10px 11px 9px}
  .nfp-rows li,.nfp-serv{font-size:0.8125rem}
}

.bn-cards{
  list-style:none;margin:12px 0 0;padding:0;
  display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;
}
.bn-card{
  padding:15px 14px 16px;border-radius:18px;
  background:var(--jade);border:1px solid var(--rule);
}
.bc-ico{
  display:grid;place-items:center;width:34px;height:34px;border-radius:50%;
  background:rgba(245,193,54,.16);color:var(--gold);
}
.bc-ico svg{width:18px;height:18px;display:block}
.bn-card b{
  display:block;margin:11px 0 0;font-family:var(--ui);
  font-size:clamp(0.9375rem,4.2vw,1.0625rem);font-weight:800;letter-spacing:-.02em;color:var(--ice);
}
.bn-card p{
  margin:5px 0 0;font-family:var(--ui);font-size:clamp(0.8125rem,3.6vw,0.90625rem);
  font-weight:500;line-height:1.4;color:var(--mist);
}
.bn-note{
  margin:16px 0 0;font-family:var(--ui);font-size:0.78125rem;font-weight:500;
  line-height:1.5;color:var(--mist);opacity:.82;max-width:70ch;
}

@media (min-width:760px){
  .bn-cards{grid-template-columns:repeat(4,minmax(0,1fr));gap:12px}
}
@media (min-width:900px){
  .benefits{padding:56px 0 18px}
  /* The photo takes a column of its own only when it can stay large doing it. */
  .bn-in{grid-template-columns:minmax(0,44%) minmax(0,1fr);gap:34px;align-items:start}
  .bn-shot{position:sticky;top:96px}
}

/* ------------------------------------------------------------------ cart --
   Built to the mockup: an offer bar, a product card with a stepper that walks
   the ladder, one rung up priced, the delivery promise, then what the order is
   made of as a plain table. Type is the theme's own — Bricolage for money and
   headings, Jakarta for everything else, Noto for CJK. Money sets with tabular
   figures so a column stays a column while it changes.

   Every vertical measure is a clamp against screen height: the same rows sit
   tight on a small phone and breathe on a large one, from one mechanism. */

.dr-ann{
  flex:0 0 auto;margin:0;padding:clamp(7px,1.3svh,12px) 16px;
  display:flex;align-items:center;justify-content:center;gap:8px;
  background:var(--gold);color:var(--ink);
  font-family:var(--ui);font-size:clamp(0.8125rem,2svh,0.9375rem);font-weight:800;
  letter-spacing:-.01em;text-align:center;
}
.ann-flag{flex:0 0 auto;display:block;width:20px;height:14px;border-radius:2px;overflow:hidden}
.ann-flag svg{width:20px;height:14px;display:block}

.dr-head{
  padding:clamp(6px,1.3svh,12px) 16px clamp(5px,1svh,10px);
  gap:11px;align-items:center;border-bottom:0;
}
.dr-back{
  flex:0 0 auto;display:grid;place-items:center;cursor:pointer;
  width:clamp(38px,5.4svh,46px);height:clamp(38px,5.4svh,46px);border-radius:50%;
  background:none;border:1.5px solid var(--glass-line);color:var(--ice);
}
/* One chevron in the sprite, pointing down. Turned a quarter to point back. */
.dr-back svg{width:14px;height:10px;transform:rotate(90deg)}
.dr-back:hover{border-color:var(--gold);color:var(--gold)}
.dr-head h2{
  flex:1 1 auto;min-width:0;display:flex;align-items:baseline;gap:9px;margin:0;
  font-family:var(--dsp);font-variation-settings:'wdth' 92,'opsz' 40;
  font-size:clamp(1.3125rem,3.5svh,1.6875rem);font-weight:800;letter-spacing:-.035em;
  line-height:1;color:var(--ice);
}
html[lang^="zh"] .dr-head h2{font-family:var(--cjk),var(--dsp);letter-spacing:0}
.dr-n{
  font-family:var(--ui);font-style:normal;font-size:clamp(0.8125rem,2svh,0.96875rem);
  font-weight:600;letter-spacing:0;color:var(--mist);white-space:nowrap;
}
.dr-n:not(:empty)::before{content:"\00B7";margin-right:7px}

.dr-lang{position:relative;flex:0 0 auto}
.dl-btn{
  display:flex;align-items:center;gap:6px;cursor:pointer;
  padding:0 12px;height:clamp(34px,4.8svh,40px);border-radius:var(--r-pill);
  background:none;border:1.5px solid var(--glass-line);color:var(--ice);
  font-family:var(--ui);font-size:0.84375rem;font-weight:800;
}
.dl-btn svg{width:11px;height:8px}
.dl-btn:hover{border-color:var(--gold);color:var(--gold)}
/* Fixed, and placed by script, because absolute could not get out. The pill
   sits inside the drawer's step band, and that band clips its own overflow so
   the durian photograph can bleed past its rounded corner — which also cut the
   menu off two options in. The band is short: the list needs about 190px and
   had 65 of them, so English and 简体中文 showed and the other two languages
   simply were not there.

   Nothing between here and the viewport carries a transform, so fixed resolves
   against the viewport and leaves both the band's overflow and the drawer's
   behind. Placement is the price, and it is paid in placeLangMenu. */
.dl-menu{
  position:fixed;z-index:60;min-width:158px;
  padding:6px;border-radius:14px;background:var(--bar);
  border:1px solid var(--glass-line);box-shadow:0 14px 30px rgba(0,0,0,.45);
}
.dl-menu button{
  display:block;width:100%;text-align:left;cursor:pointer;
  padding:10px 12px;border:0;border-radius:9px;background:none;color:var(--ice);
  font-family:var(--ui);font-size:0.875rem;font-weight:700;
}
.dl-menu button:hover{background:var(--glass);color:var(--gold)}

.dr-body{padding:0 16px clamp(7px,1.3svh,12px)}

/* The product card: what it is, what one costs, then how many and what that
   comes to. The stepper counts fruit and walks the ladder. */
.drawer .line{
  /* The base .line is a flex row for the page's own use; without this the two
     rows of the card lay out side by side and print over each other. */
  display:block;
  margin:clamp(7px,1.4svh,14px) 0 0;padding:clamp(9px,1.6svh,15px) clamp(10px,1.5svh,14px);
  background:var(--card);border:1px solid var(--rule);border-radius:18px;
}
.drawer .line + .line{border-top:1px solid var(--rule)}
.drawer .line-top{display:flex;gap:13px;align-items:flex-start;padding:0}
.line-ph{
  flex:0 0 auto;display:grid;place-items:center;overflow:hidden;
  width:clamp(52px,7.4svh,66px);height:clamp(52px,7.4svh,66px);
  border-radius:15px;background:var(--jade);border:1px solid rgba(245,193,54,.28);
}
.line-ph img{width:100%;height:100%;object-fit:cover;display:block}
.line-ph .fr{width:64%;height:64%}
.drawer .line-m{flex:1 1 auto;min-width:0}
/* Ceiling dropped from 18.5px to 17px because the line got longer: the box
   name now carries the cultivar, and "16 lb Musang King box · Serves 8-10" at
   18.5px took three lines in this 155px column and pushed the drawer 12px past
   the one-screen fit. At 17px it is two lines and the fit comes back. */
.drawer .line-m b{
  display:block;font-family:var(--ui);font-size:clamp(0.96875rem,2.3svh,1.0625rem);
  font-weight:800;letter-spacing:-.02em;line-height:1.2;color:var(--ice);
}
.line-spec{
  display:block;margin-top:4px;font-family:var(--ui);
  font-size:clamp(0.78125rem,1.95svh,0.875rem);font-weight:600;line-height:1.3;color:var(--gold-soft);
}
.line-each{
  display:block;margin-top:5px;font-family:var(--ui);
  font-size:clamp(0.84375rem,2.1svh,0.96875rem);font-weight:600;color:var(--mist);
  font-variant-numeric:tabular-nums;
}
.line-each s{color:var(--mist);opacity:.62;margin-right:7px;text-decoration-thickness:1.5px}
.line-each em{font-style:normal;font-weight:800;color:var(--ice)}

.line-bot{
  display:flex;align-items:center;justify-content:space-between;gap:12px;
  margin-top:clamp(5px,1.1svh,10px);padding-top:clamp(5px,1.1svh,10px);
  border-top:1px solid var(--rule);
}
.line-step{
  display:inline-flex;align-items:center;gap:2px;
  border-radius:var(--r-pill);background:var(--deep);border:1px solid var(--rule);
  padding:3px;
}
.ls-b{
  display:grid;place-items:center;cursor:pointer;
  width:clamp(38px,5.2svh,44px);height:clamp(34px,4.8svh,40px);
  border:0;border-radius:var(--r-pill);background:none;color:var(--ice);
}
.ls-b svg{width:16px;height:16px}
.ls-b:hover:not(:disabled){background:var(--glass);color:var(--gold)}
.ls-b:disabled{color:var(--mist);opacity:.34;cursor:not-allowed}
/* Remove reads as an exit, not as a step. */
.ls-b.is-del{color:var(--mist)}
.ls-b.is-del svg{width:13px;height:13px}
.ls-b.is-del:hover{background:rgba(255,255,255,.06);color:var(--ice)}
.ls-b:focus-visible{outline:2px solid var(--gold);outline-offset:-3px}
/* The value in the stepper is a weight now, not a bare count, and the box it
   sits in was 30px wide with nothing stopping it wrapping — so "27 lb" broke
   after the numeral and the pill grew a second line. Wide enough for the
   longest of them, and it does not wrap. */
.ls-n{
  min-width:58px;text-align:center;white-space:nowrap;font-family:var(--dsp);
  font-variation-settings:'wdth' 92,'opsz' 40;font-size:clamp(1.125rem,2.8svh,1.3125rem);
  font-weight:800;color:var(--ice);font-variant-numeric:tabular-nums;
  line-height:1.05;
}
/* The unit is not the figure. Set smaller and lighter it stops competing with
   the number a shopper is actually reading, and the pair takes less width. */
.ls-u{
  font-style:normal;font-family:var(--ui);font-size:.6em;font-weight:700;
  margin-left:3px;opacity:.72;letter-spacing:.01em;
}
html[lang^="zh"] .ls-u{font-family:var(--cjk),var(--ui);margin-left:1px}
.line-amt{
  font-family:var(--dsp);font-variation-settings:'wdth' 92,'opsz' 40;
  font-size:clamp(1.5rem,3.8svh,1.875rem);font-weight:800;letter-spacing:-.035em;
  line-height:1;color:var(--ice);font-variant-numeric:tabular-nums;
}

/* One rung up, priced. A whole tappable row, because it is an offer. */
#dr-up{margin-top:clamp(5px,1.3svh,13px)}
.up-in{
  display:flex;width:100%;align-items:center;gap:11px;cursor:pointer;text-align:left;
  padding:clamp(6px,1.4svh,13px) 13px;border-radius:15px;
  border:1.5px solid rgba(245,193,54,.5);background:rgba(245,193,54,.07);
  font-family:var(--ui);font-size:clamp(0.78125rem,2svh,0.9375rem);font-weight:700;
  color:var(--ice);line-height:1.22;
}
.up-in:hover{background:rgba(245,193,54,.13)}
.up-in:focus-visible{outline:2px solid var(--gold);outline-offset:3px}
.up-ico{
  flex:0 0 auto;display:grid;place-items:center;
  width:clamp(26px,3.8svh,32px);height:clamp(26px,3.8svh,32px);border-radius:50%;
  background:var(--gold);color:var(--ink);
}
.up-ico svg{width:15px;height:15px}
.up-copy b{color:var(--gold);font-weight:800}

/* The delivery promise. */
.dr-eta{
  display:flex;align-items:center;gap:11px;margin:clamp(7px,1.3svh,13px) 0 0;
  padding:clamp(8px,1.4svh,13px) 13px;border-radius:15px;
  background:var(--card);border:1px solid var(--rule);
}
.de-ico{
  flex:0 0 auto;display:grid;place-items:center;color:var(--gold);
  width:clamp(24px,3.4svh,28px);height:clamp(24px,3.4svh,28px);
}
.de-ico svg{width:100%;height:100%}
.de-copy{flex:1 1 auto;min-width:0}
.de-copy b{
  display:block;font-family:var(--ui);font-size:clamp(0.875rem,2.2svh,1rem);
  font-weight:800;letter-spacing:-.015em;line-height:1.2;color:var(--ice);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.de-copy i{
  display:block;margin-top:2px;font-style:normal;font-family:var(--ui);
  font-size:clamp(0.75rem,1.85svh,0.84375rem);font-weight:600;color:var(--mist);
}
.de-free{
  flex:0 0 auto;padding:5px 13px;border-radius:var(--r-pill);
  background:var(--gold);color:var(--ink);
  font-family:var(--ui);font-size:0.84375rem;font-weight:800;letter-spacing:.03em;
}

/* What the order is made of. Rows, not cards — this is a statement of account. */
.dr-tbl{margin-top:clamp(10px,1.8svh,18px)}
.tb-row{
  display:flex;align-items:baseline;justify-content:space-between;gap:14px;
  padding:clamp(2px,.85svh,8px) 2px;border-bottom:1px solid var(--rule);
}
.tb-row:last-child{border-bottom:0}
.tb-k{
  font-family:var(--ui);font-size:clamp(0.875rem,2.2svh,1rem);font-weight:600;color:var(--ice);
  min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.tb-v{
  flex:0 0 auto;display:flex;align-items:baseline;gap:9px;
  font-family:var(--ui);font-size:clamp(0.875rem,2.2svh,1rem);font-weight:800;
  color:var(--ice);font-variant-numeric:tabular-nums;
}
.tb-v s{color:var(--mist);opacity:.62;font-weight:600;text-decoration-thickness:1.5px}
.tb-v b.free{color:var(--gold)}

/* The total, and everything the shopper is not paying. */
.dr-tot{
  display:flex;align-items:center;justify-content:space-between;gap:14px;
  margin:0 0 clamp(4px,1svh,9px);padding:clamp(4px,1svh,10px) 14px;
  border:0;border-radius:16px;background:var(--jade-lift);
}
.dt-l{min-width:0}
.dt-l b{
  display:block;font-family:var(--dsp);font-variation-settings:'wdth' 92,'opsz' 40;
  font-size:clamp(1.0625rem,2.7svh,1.4375rem);font-weight:800;letter-spacing:-.03em;
  line-height:1;color:var(--ice);
}
html[lang^="zh"] .dt-l b{font-family:var(--cjk),var(--dsp);letter-spacing:0}
.dt-save{
  display:block;margin-top:3px;font-style:normal;font-family:var(--ui);
  font-size:clamp(0.75rem,1.85svh,0.84375rem);font-weight:800;color:var(--gold);
  font-variant-numeric:tabular-nums;
}
.dt-v{
  flex:0 0 auto;font-family:var(--dsp);font-variation-settings:'wdth' 92,'opsz' 40;
  font-size:clamp(1.75rem,4.4svh,2.3125rem);font-weight:800;letter-spacing:-.04em;
  line-height:1;color:var(--ice);font-variant-numeric:tabular-nums;
}

.dr-foot{
  padding:clamp(6px,1.35svh,14px) 16px
  calc(clamp(6px,1.35svh,14px) + env(safe-area-inset-bottom,0px));
  border-top:1px solid var(--rule);
}
.dr-guar{
  display:block;margin:clamp(3px,.95svh,11px) 0 0;text-align:center;
  font-family:var(--ui);font-size:clamp(0.71875rem,1.8svh,0.84375rem);font-weight:700;
  line-height:1.35;color:var(--mist);
}
.drawer.empty .dr-tbl,.drawer.empty .dr-ann{display:none}

/* Under 760px the panel is short of the room it needs. The banner is the one
   thing in it that is said twice — "Overnight shipping / $49 / FREE" sits two
   inches below it in the table, with the figure attached. Everything the table
   does not already carry stays. */
@media (max-height:759px){
  .dr-ann{display:none}
}

/* Remove sits under the price now rather than on a rule of its own — the
   price column was the shortest of the three and had the room for free. */
.line-amt{display:flex;flex-direction:column;align-items:flex-end;gap:2px}
.line-amt .line-del{margin-top:3px;padding:0;font-size:0.78125rem}



/* ---------- the money ---------- */
/* Now in the footer: it needs its own top rule and no top margin, since the
   footer already draws the divider above it. */
.dr-sums{padding:0 0 clamp(8px,1.2svh,11px);margin:0 0 clamp(9px,1.4svh,13px);
  border-top:0;border-bottom:1px solid var(--rule)}
.dr-row{display:flex;justify-content:space-between;gap:14px;font-size:0.90625rem;color:var(--mist);padding:0}
.dr-row > b,.dr-row b{color:var(--gold);font-weight:800}
.dr-shipv{display:inline-flex;align-items:baseline;gap:9px}
.dr-shipv s{color:var(--mist);opacity:.72;font-weight:500;text-decoration-thickness:1.5px;
  font-variant-numeric:tabular-nums}
.dr-tot{display:flex;justify-content:space-between;align-items:baseline;gap:14px;
  margin-top:clamp(3px,.7svh,6px);padding-top:clamp(5px,1.1svh,10px);
  border-top:1px solid var(--rule)}
.dr-tot span:first-child{font-size:1.1875rem;font-weight:800;color:var(--ice)}
.dr-tot span:last-child{font-family:var(--dsp);font-variation-settings:'wdth' 92,'opsz' 60;
  font-size:2rem;font-weight:800;letter-spacing:-.045em;color:var(--ice);
  font-variant-numeric:tabular-nums;line-height:1}

/* ---------- when it lands ---------- */
.dr-eta{display:flex;gap:9px;align-items:center;justify-content:center;margin:11px 0 0;
  font-family:var(--ui);font-size:0.90625rem;font-weight:800;line-height:1.35;
  color:var(--gold);text-align:center}
html[lang^="zh"] .dr-eta{font-family:var(--cjk),var(--ui)}
.dr-eta svg{flex:0 0 auto;width:17px;height:17px;fill:currentColor;display:block}

/* ---------- the way out ---------- */
.dr-foot{padding:clamp(12px,1.7svh,17px) 18px
  calc(clamp(12px,1.7svh,17px) + env(safe-area-inset-bottom,0px));border-top:1px solid var(--rule)}
.dr-foot form{margin:0}
.dr-cta{display:flex;align-items:center;justify-content:center;gap:10px;width:100%;
  min-height:clamp(50px,7svh,60px);padding:clamp(10px,1.8svh,16px) 15px;
  font-size:clamp(1.0625rem,2.7svh,1.3125rem);font-weight:800;letter-spacing:-.02em}
html[lang^="zh"] .dr-cta{letter-spacing:0;font-size:1.1875rem}
.dr-lock{flex:0 0 auto;width:19px;height:19px;fill:none;stroke:currentColor;
  stroke-width:2;stroke-linecap:round;stroke-linejoin:round;display:block}

/* Shopify draws the wallet buttons inside a shadow root, so ordinary
   selectors cannot reach them — these custom properties are the only
   supported way in. */
/* ------------------------------------ one-tap checkout, on the buy panel ----
   Quieter than the Add button above it and clearly its junior: a small label,
   then Shopify's own buttons at a shorter height than the gold one. The point
   is that a shopper who already knows what they want can skip both the cart
   and the address form, not that they should be pulled away from the main
   decision. Shopify draws and brands these itself; what is set here is only
   their size, spacing and how they sit in the column.

   :empty collapses the whole block, so a shop with no wallets enabled gets the
   label and its margin removed rather than a stranded heading. */
/* ------------------------------------------- one wallet, then the rest ----
   Each block is capped at the height of a single button and opens on request.
   The cap is expressed as the same measurement that sets the button height, so
   the two cannot drift apart; --dx-one is set per block because the cart's
   buttons are 48px and the buy panel's are 54px.

   Deliberately a height rather than a selector. Shopify owns what goes in
   here and renames its internals between releases — anything that reached in
   to hide the second child would break silently on their next deploy, and the
   symptom would be five stacked pills again with nobody watching. */
/* The wallet the device can actually use, first.

   Shopify renders one button per wallet in a flex column, in the order the
   shop's payment settings put them — the same order on every device. With the
   row clipped to a single button that means an iPhone could be shown Google
   Pay and an Android phone Apple Pay, each being offered the one wallet they
   do not have. Order costs nothing and reorders only what is drawn.

   Everything else keeps its place: order 0 is the default, so Shop Pay and
   PayPal stay exactly where Shopify put them relative to each other. */
.dx-clip > *{display:flex;flex-direction:column}
.dg-apple .dx-clip [data-testid*="apple" i],
.dg-apple .dx-clip [aria-label*="Apple" i],
.dg-apple .dx-clip [class*="apple-pay" i]{order:-1}
.dg-android .dx-clip [data-testid*="google" i],
.dg-android .dx-clip [aria-label*="Google" i],
.dg-android .dx-clip [class*="google-pay" i]{order:-1}

.dx-clip{max-height:var(--dx-one,48px);overflow:hidden}
.dg-express.open .dx-clip,.dr-express.open .dx-clip{max-height:none;overflow:visible}
.dx-more{
  display:block;width:100%;margin-top:9px;padding:11px 8px;min-height:44px;
  background:none;border:0;cursor:pointer;
  font-family:var(--ui);font-size:0.875rem;font-weight:700;color:var(--mist);
  text-decoration:underline;text-underline-offset:3px;
}
.dx-more[hidden]{display:none}
.dx-more:hover{color:var(--gold)}
.dx-more:focus-visible{outline:2px solid var(--gold);outline-offset:2px;border-radius:8px}
@media (prefers-reduced-motion:no-preference){
  .dx-clip{transition:max-height .26s cubic-bezier(.3,.8,.4,1)}
}

.dg-express{--dx-one:54px}
.dr-express{--dx-one:48px}
.dg-express{margin-top:14px}
/* Collapsed unless Shopify actually drew a button. The label is always a child
   of this block, so an :empty test could never have caught the case that
   matters — a shop with no wallets switched on would have rendered the words
   "or check out in one tap" above nothing at all. */
.dg-express:not(:has(.shopify-payment-button)){display:none}
.dgx-lab{
  display:block;text-align:center;margin:0 0 9px;
  font-family:var(--ui);font-size:0.8125rem;font-weight:700;
  letter-spacing:.02em;color:var(--mist);
}
html[lang^="zh"] .dgx-lab{font-family:var(--cjk),var(--ui);letter-spacing:.04em}
.dg-express .shopify-payment-button{
  --shopify-accelerated-checkout-button-block-size:54px;
  --shopify-accelerated-checkout-button-border-radius:var(--r-pill);
  --shopify-accelerated-checkout-row-gap:9px;
  --shopify-accelerated-checkout-inline-alignment:stretch;
  --shopify-accelerated-checkout-button-inline-size:100%;
  --shopify-accelerated-checkout-button-box-shadow:none;
  display:block;width:100%;
}
/* Shopify's own "more payment options" link, which opens a second list. It is
   a text link on a dark ground and inherits nothing, so it is stated here. */
.dg-express .shopify-payment-button__more-options{
  display:block;width:100%;margin-top:9px;padding:10px;
  background:none;border:0;cursor:pointer;
  font-family:var(--ui);font-size:0.875rem;font-weight:700;color:var(--mist);
  text-decoration:underline;text-underline-offset:3px;
}
.dg-express .shopify-payment-button__more-options:hover{color:var(--gold)}

.dr-express{
  margin-top:9px;
  --shopify-accelerated-checkout-button-block-size:48px;
  --shopify-accelerated-checkout-button-border-radius:var(--r-pill);
  --shopify-accelerated-checkout-row-gap:8px;
  --shopify-accelerated-checkout-inline-alignment:stretch;
  --shopify-accelerated-checkout-button-inline-size:100%;
  --shopify-accelerated-checkout-button-box-shadow:none;
}
.dr-express[hidden],.dr-express:empty{display:none}
.dr-express .dynamic-checkout__content,
.dr-express [data-shopify-buttoncontainer]{width:100%}

.dr-guar{display:flex;gap:8px;align-items:center;justify-content:center;
  margin:clamp(6px,1.1svh,11px) 0 0;
  font-size:0.8125rem;line-height:1.4;color:var(--mist);text-align:center}
.dr-guar svg{flex:0 0 auto;width:15px;height:15px;color:var(--gold);fill:none;
  stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;display:block}
.dr-pay{display:flex;flex-wrap:wrap;gap:6px;justify-content:center;margin-top:9px}
/* Shopify's payment_type_svg_tag takes a class, but the row must not depend
   on getting it - anything the shop has enabled is sized by being in here. */
.dr-pay > svg,.dr-pay > img{height:24px;width:auto;display:block;border-radius:5px}
.dr-pay > img.dr-zelle{border-radius:0}

/* ---------- empty ----------
   An empty cart has nothing to check out, so the footer goes entirely
   rather than sitting there as a disabled slab of gold twice the size of
   the message above it. */
.drawer.empty .dr-foot{display:none}
.drawer.empty .dr-body{display:flex;flex-direction:column;min-height:250px;padding-bottom:24px}
.drawer.empty #dr-lines{
  flex:1 1 auto;display:flex;flex-direction:column;align-items:center;justify-content:center;
  text-align:center;gap:20px;padding:36px 0 8px;
}
.dr-empty{margin:0;padding:0;font-size:1.125rem;line-height:1.5;color:var(--mist);max-width:24ch}
.dr-empty-cta{
  /* an explicit width: a centred flex item otherwise shrinks to its text */
  width:min(320px,100%);min-height:58px;cursor:pointer;border:0;
  border-radius:var(--r-pill);background:var(--gold);color:var(--abyss);
  font-family:var(--ui);font-size:1.125rem;font-weight:800;letter-spacing:-.015em;
}
.dr-empty-cta:focus-visible{outline:3px solid var(--ice);outline-offset:3px}

/* ---------- small phones ---------- */
@media (max-width:359px){
  .dr-lang button{font-size:0.84375rem}
  .line-step button{width:42px}
  .sv-add{padding:0 13px;font-size:0.90625rem}
  .dr-tot span:last-child{font-size:1.75rem}
  .dr-cta{font-size:1.125rem}
}

/* ============================================================
   Fold compaction.
   The decision now fits on the first screen. The card keeps the
   per-fruit price as its largest number and puts the total beside
   the weight; the thumbnail strip becomes the dot indicator it was
   already behaving like; and everything that reassures rather than
   decides moved below the button.
   ============================================================ */

@media (max-width:899px){
  /* Square, and always the full width of the column — never narrower than the
     thumbnail strip beneath it.

     A max-height here is the trap. With aspect-ratio:1/1 the browser satisfies
     a height cap by shrinking the WIDTH to keep the square, so on any viewport
     under about 813px tall the photo came in narrower than its own thumbnails.
     Measured at 390x700: 308px of photo against 358px of strip. */
  .shot{aspect-ratio:1/1;max-height:none;width:auto}

  /* Real thumbnails, back by request, and the strip has to end exactly where
     the photograph above it ends. Seven slides across seven columns with six
     gaps — no scroll, no seventh thumb hanging off the right edge. The 16px
     side padding is the gallery's own margin, so both edges line up. */
  /* Six at a time, and the strip is exactly as wide as the photograph above
     it. The side gutter is a MARGIN, not padding — with padding the scroll
     container is the full 390 and the seventh thumb shows through the gutter,
     past the edge of the image. As a margin the box is 358 and clips flush.

     Nothing is padded on either axis: the selection ring is drawn inside the
     thumbnail now, so the strip has nothing to make room for. */
  .thumbs{--g:6px;margin:9px 16px 4px;padding:0;overflow-x:auto}
  .thumbs figure{flex:0 0 calc((100% - 5 * var(--g)) / 6);border-radius:10px}

  /* The spec band stays gold — it is brand, and AAA/D197 is the grade claim
     that justifies the price — it just stops being a 48px slab. */
  .spec{margin:11px 20px 0;padding:7px 14px;font-size:0.90625rem}
}

/* ---- the card: two rows, per-fruit still the largest number on it ---- */
.buy .tier{padding:12px 14px 11px}
.t-unitwrap{
  margin-left:auto;flex:0 0 auto;display:flex;align-items:baseline;gap:6px;
  white-space:nowrap;min-width:0;
}
.t-unitwrap .t-unit{font-size:1.625rem}

@media (min-width:900px){
  .t-unitwrap .t-unit{font-size:1.875rem}
}
@media (max-width:359px){
  .t-unitwrap .t-unit{font-size:1.375rem}
  .t-r1{gap:9px}
}

.t-more{margin-top:13px}

/* The rest of the fold's slack: padding that was sized for a page whose buy
   panel started 300px lower than it does now. */
@media (max-width:899px){
  .head{padding-top:10px}
  .buy{padding-top:12px}
  .buy .tiers{gap:8px}
  .buy .cta{margin-top:14px}
}


/* ============================================================
   The wordmark.
   Heavier, and the second half moves from amber-gold to an actual
   yellow — at 20px on a phone the old #F5C136 sat too close to the
   ice half to separate at a glance.
   ============================================================ */
.mark b{font-weight:900;letter-spacing:-.03em}
.bar .mark b{letter-spacing:-.022em}
.mark i{color:var(--mark-yellow);text-shadow:0 0 24px rgba(255,209,31,.42)}

/* ============================================================
   Adding to the cart.
   The add used to be silent: the drawer simply appeared. Now the
   button confirms, the bag count kicks, and the drawer opens on a
   reward. All of it is behind prefers-reduced-motion; with motion
   off the same states are reached, just without the movement.
   ============================================================ */

/* the button, on success */
.cta.ok,.dock button.ok{background:var(--gold-soft)}
@media (prefers-reduced-motion:no-preference){
  .cta.ok,.dock button.ok{animation:dgPop .42s cubic-bezier(.2,.9,.3,1)}
  .cartn.bump{animation:dgBump .52s cubic-bezier(.2,.9,.3,1)}
}
@keyframes dgPop{0%{transform:scale(1)}38%{transform:scale(1.04)}100%{transform:scale(1)}}
@keyframes dgBump{0%{transform:scale(1)}34%{transform:scale(1.55)}100%{transform:scale(1)}}

/* the reward */
.dr-unlock{
  display:flex;gap:13px;align-items:center;margin:14px 0 0;padding:12px 14px;
  position:relative;overflow:hidden;border-radius:16px;
  border:1.5px solid rgba(245,193,54,.55);
  background:linear-gradient(118deg,rgba(245,193,54,.20),rgba(245,193,54,.09));
}
.dr-unlock[hidden]{display:none}
.ul-ico{
  flex:0 0 auto;width:44px;height:44px;border-radius:13px;display:grid;place-items:center;
  background:var(--gold);color:var(--abyss);
}
.ul-ico svg{grid-area:1/1;width:23px;height:23px;fill:none;stroke:currentColor;
  stroke-width:1.9;stroke-linecap:round}
/* Resting state is the OPEN lock, so with motion disabled the banner still
   reads as unlocked rather than as a padlock that never opened. */
.ul-shut{opacity:0}
.ul-open{opacity:1}
.ul-copy{min-width:0}
.ul-copy b{display:block;font-family:var(--ui);font-size:1.03125rem;font-weight:800;
  letter-spacing:-.015em;line-height:1.25;color:var(--gold)}
.ul-copy i{display:block;font-style:normal;font-size:0.875rem;line-height:1.4;
  color:var(--mist);margin-top:3px}
html[lang^="zh"] .ul-copy b{font-family:var(--cjk),var(--ui);letter-spacing:0}

@media (prefers-reduced-motion:no-preference){
  .dr-unlock.go{animation:dgUnlockIn .48s cubic-bezier(.2,.85,.3,1) both}
  .dr-unlock.go .ul-shut{animation:dgShackleOut .38s ease both}
  .dr-unlock.go .ul-open{animation:dgShackleIn .26s ease .34s both}
  .dr-unlock.go::after{
    content:"";position:absolute;inset:0;pointer-events:none;
    background:linear-gradient(100deg,transparent 32%,rgba(255,255,255,.28) 50%,transparent 68%);
    transform:translateX(-100%);animation:dgSheen .9s ease .26s 1;
  }
}
@keyframes dgUnlockIn{from{opacity:0;transform:translateY(-10px) scale(.975)}to{opacity:1;transform:none}}
@keyframes dgShackleOut{0%,72%{opacity:1;transform:none}100%{opacity:0;transform:scale(.72)}}
@keyframes dgShackleIn{from{opacity:0;transform:scale(.72)}to{opacity:1;transform:none}}
@keyframes dgSheen{to{transform:translateX(100%)}}

@media (max-width:359px){
  .ul-copy b{font-size:0.9375rem}
  .ul-ico{width:40px;height:40px}
}

/* The banner is a moment, not a permanent row. It costs 100px, which is exactly
   enough to push this cart into a scroll — so once it has been seen it collapses
   itself and hands the space back. */
.dr-unlock.bye{animation:dgUnlockOut .45s cubic-bezier(.4,0,.6,1) both}
@keyframes dgUnlockOut{
  0%{opacity:1;max-height:150px;margin-top:14px;padding-top:12px;padding-bottom:12px;
     border-top-width:1.5px;border-bottom-width:1.5px}
  100%{opacity:0;max-height:0;margin-top:0;padding-top:0;padding-bottom:0;
     border-top-width:0;border-bottom-width:0}
}

/* ------------------------------------------------------------- ombre -----
   The fold was flat: one green from the top of the photograph to the bottom
   of the buy panel, and every card on it sat on exactly the same value. A
   light source at the top gives the whole thing somewhere to be — the panel
   reads as lit rather than filled.

   It resolves to the page's own ground before the fold ends, so there is no
   seam where the next section starts, and nothing below the fold changes. */
/* .fold and .fold-buy are display:contents — they have no box, so they cannot
   carry it. The element that actually spans the photograph and the buy panel
   is the page. Stops are in pixels rather than percentages so the light lands
   over the fold whatever the page below it grows to, and the last colour is
   the ground the rest of the page already stands on. */
body.dg74{
  background-color:var(--abyss);
  background-image:
    radial-gradient(150% 720px at 50% -90px,
      rgba(44,150,101,.92) 0%, rgba(44,150,101,.3) 46%, rgba(44,150,101,0) 100%),
    linear-gradient(180deg, #124A31 0px, var(--abyss) 1500px);
  background-repeat:no-repeat;
}
/* And the buy panel settles a shade further, the way the reference card does
   — the deepest point of the fold is where the money is. */
.buy{
  background:linear-gradient(180deg,
    rgba(4,20,13,0) 0%, rgba(4,20,13,.22) 55%, rgba(4,20,13,.42) 100%);
  /* The 34px that used to separate the buy panel from the cream section was
     .how-wrap's top margin, which sits outside this gradient — so the fold's
     darkest edge stopped 34px short of the cream and that strip showed the
     undarkened page green as a lighter band. Same gap, moved inside the box
     that paints it. Every earlier .buy padding shorthand is above this rule,
     so this wins; keep it that way. */
  padding-bottom:34px;
  /* Chinese sets a larger title, which makes the panel's height fractional and
     leaves a sub-pixel line of undarkened ground under it. A pixel of overlap
     costs nothing in rhythm and closes it in every language. */
  margin-bottom:-1px;
}

/* ------------------------------------------------- purchase options -------
   Rows, not a grid. Six boxes in a grid is six things to compare at once; as
   rows the shopper reads one line each and only the chosen box opens up, so
   the whole set costs about one card's height. Type is the theme's own —
   Bricolage for the money, Jakarta for everything else. */
/* The header row is gone: the step band carries the title, the line under it
   and the fruit in one block. */

.buy .tiers{display:flex;flex-direction:column;gap:7px;grid-template-columns:none}
/* An older generation spaced the cards with a bottom margin; on top of the gap
   that was 19px between rows. */
.buy .tier{margin:0}
.buy .tier{
  display:block;position:relative;cursor:pointer;padding:0;overflow:hidden;
  border-radius:20px;border:2px solid var(--glass-line);background:rgba(255,255,255,.05);
  transition:border-color .15s ease,background .15s ease,box-shadow .15s ease;
}
.buy .tier.on{
  border-color:var(--gold);
  background:linear-gradient(180deg,rgba(245,193,54,.2),rgba(245,193,54,.06));
  box-shadow:0 10px 24px rgba(0,0,0,.3);
}
.buy .tier.oos{opacity:.5}
/* One ring, not two. :focus-within fires on a mouse tap as well as a keyboard
   one, so every selected row was drawing a gold outline 2px outside the gold
   border it already has. The keyboard still gets its ring. */
.buy .tier:focus-within{outline:none}
.buy .tier:has(input:focus-visible){outline:3px solid var(--gold);outline-offset:3px}

.buy .t-r1{
  order:0;display:flex;align-items:center;gap:12px;
  padding:10px 14px;min-height:72px;
}
.buy .tier input[name="qty"]{position:absolute;opacity:0;width:1px;height:1px;pointer-events:none}
.t-dot{
  flex:none;width:26px;height:26px;border-radius:50%;display:grid;place-items:center;
  border:2px solid rgba(234,244,238,.38);color:var(--ink);
  font-family:var(--ui);font-weight:900;font-size:0.8125rem;line-height:1;
}
.tier.on .t-dot{border-color:var(--gold);background:var(--gold)}
.tier.on .t-dot::after{content:"\2713"}
.t-mid{flex:1 1 auto;min-width:0}
/* The card clips, so the name must not be shrinkable — "4 Durians" losing its
   noun to a badge beside it is how it became "4". */
.t-l1{display:flex;align-items:center;flex-wrap:wrap;gap:4px 7px;min-width:0}
.buy .t-qty{
  flex:0 0 auto;font-family:var(--ui);font-size:1.0625rem;font-weight:800;
  letter-spacing:-.02em;color:var(--ice);white-space:nowrap;
}
/* The badge is a strip across the top of the card, not a pill beside the box
   name. As a full-width band it reads at a glance from the ladder — which is
   the whole job of "most popular" — and it stops competing for horizontal room
   with the box name, which is what forced the 12px type and the tight
   letter-spacing on a narrow phone.

   No radius and no offsets: .tier already has overflow:hidden and its own
   radius, so the strip's top corners are clipped to match the card exactly and
   cannot drift out of step with it. */
.buy .t-rec{
  position:static;display:block;width:100%;box-sizing:border-box;
  flex:none;font-style:normal;
  padding:6px 12px;border-radius:0;
  background:var(--gold);color:var(--ink);box-shadow:none;
  font-family:var(--ui);font-size:0.8125rem;font-weight:800;letter-spacing:.09em;
  text-transform:uppercase;white-space:nowrap;text-align:center;
}
/* Both strips carry the same gold. They were deliberately different — the
   softer tone on "best value" so the pre-selected card kept the eye — but two
   golds a half-step apart read as an inconsistency rather than as a hierarchy,
   and the 27 lb card is the one with the best margin, so weakening it was
   working against the shop. Selection is already signalled by the card's own
   border and check. */
.buy .t-rec--value{background:var(--gold)}
.buy .t-rec::after{content:none}
/* Earlier generations lifted the badge out of the flow and centred it over the
   card's top edge, and tinted the saving like a chip. In a row both are
   ordinary inline things and the leftover transform was dragging the badge
   over the radio dot. */
.buy .tier.on .t-rec{transform:none;top:auto;left:auto;right:auto;bottom:auto}
.buy .tier .t-save,.buy .tier.on .t-save{background:none;box-shadow:none;border:0}
.buy .tier.on .t-save{color:var(--gold-soft)}
@media (max-width:409px){
  .buy .t-rec{font-size:0.78125rem;padding:6px 10px;letter-spacing:.07em}
}
.t-l2{display:flex;align-items:center;gap:8px;margin-top:5px;min-width:0}
/* The total is the card's headline figure. It moved from the small line on the
   left to the large slot on the right, and the per-pound rate moved the other
   way — the shopper is choosing between $150, $240 and $300, so that is what is
   set large. */
.buy .t-right .t-tot{
  display:block;margin:0;font-style:normal;
  font-family:var(--dsp);font-variation-settings:'wdth' 92,'opsz' 40;
  font-size:clamp(1.6875rem,7.4vw,2rem);font-weight:800;letter-spacing:-.04em;line-height:1;
  color:var(--ice);font-variant-numeric:tabular-nums;white-space:nowrap;
}
.t-save{
  /* An older generation floated this as a badge off the card's top corner;
     in a row it belongs beside the total it is a saving on. */
  position:static;top:auto;right:auto;padding:0;background:none;border:0;
  text-decoration:none;font-family:var(--ui);font-size:0.8125rem;font-weight:800;
  color:var(--gold-soft);font-variant-numeric:tabular-nums;white-space:nowrap;
}
.t-right{flex:none;text-align:right}
/* The rate, now the supporting line beside the saving. Inline, so its own
   "a pound" / 每磅 sits with it rather than under it. */
.buy .t-unitwrap{display:inline;white-space:nowrap}
.buy .t-unit{
  font-family:var(--ui);font-size:0.875rem;font-weight:700;letter-spacing:0;
  color:var(--mist);font-variant-numeric:tabular-nums;
}
/* Gold is for the badge, the saving and the check. The name and the unit price
   stay cream on the chosen row too — turning them gold as well left nothing on
   the card that was not shouting. */
.buy .tier.on .t-qty{color:var(--ice)}
.buy .tier.on .t-unit,.buy .tier.on .t-pre,.buy .tier.on .t-post{color:var(--mist)}
.buy .tier.on .t-tot{color:var(--ice)}
/* Shown again: while the rate was the headline it had "PER POUND" spelled out
   beneath it, so these were redundant. As a small inline figure it needs its
   own unit, and these are what carry it in each language — English puts it
   after, Chinese before. */
.buy .t-pre,.buy .t-post{display:inline;font-size:0.875rem;font-weight:600;color:var(--mist)}
.t-perlbl{
  display:block;margin-top:4px;font-style:normal;font-family:var(--ui);
  font-size:0.71875rem;font-weight:800;letter-spacing:.1em;text-transform:uppercase;
  color:rgba(234,244,238,.5);white-space:nowrap;
}
.t-x{
  /* Sits with the fruit it counts, a step off the last one. */
  flex:none;margin:0 0 6px 9px;padding:4px 10px;border-radius:var(--r-pill);
  background:var(--gold);color:var(--ink);
  font-family:var(--ui);font-size:0.9375rem;font-weight:900;line-height:1.15;
  letter-spacing:-.02em;font-variant-numeric:tabular-nums;
}
/* Kept in the markup for the script that localises the units, out of the
   picture that the open row is. */
.t-pico{
  flex:none;width:38px;height:38px;border-radius:12px;display:grid;place-items:center;
  background:rgba(245,193,54,.15);border:1px solid rgba(245,193,54,.45);color:var(--gold-soft);
}
.t-pico svg{width:20px;height:20px;display:block}

/* "More box sizes" reads as the dashed way out of a closed set. */
.t-more{
  width:100%;margin:11px 0 0;min-height:46px;display:grid;place-items:center;
  border-radius:var(--r-pill);border:1.5px dashed rgba(234,244,238,.28);background:none;
  font-family:var(--ui);font-size:0.84375rem;font-weight:800;color:rgba(255,201,77,.95);
  cursor:pointer;
}
.t-more:hover{border-color:rgba(255,201,77,.55)}
.cta-fine{
  margin:10px 0 0;text-align:center;font-family:var(--ui);font-size:0.78125rem;
  font-weight:600;color:rgba(234,244,238,.52);line-height:1.4;
}
@media (max-width:359px){
  .buy .t-r1{gap:9px;padding:9px 11px;min-height:66px}
  .buy .t-qty{font-size:0.96875rem}
  .t-pico{width:33px;height:33px}
}

/* ============================================================
   The sold count, in the cart.
   The gallery flag has been gold foil with a travelling glint
   since v74; the cart was showing the same claim on flat paint.
   Same foil, same glint, and it only runs while the drawer is
   actually open.
   ============================================================ */
.dp-sold{
  position:relative;overflow:hidden;color:var(--ink);
  background:
    linear-gradient(158deg,
      #FFEEB4 0%, #FBD35C 16%, var(--gold) 34%,
      #DCA518 52%, #FFDD6B 68%, #F0BA2C 84%, #DFA415 100%);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.6), inset 0 -1px 0 rgba(120,79,0,.28);
}
.dp-sold b{text-shadow:0 1px 0 rgba(255,255,255,.4)}
.dp-sold::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(104deg,
    rgba(255,255,255,0) 40%, rgba(255,255,255,.75) 48%,
    rgba(255,255,255,.2) 53%, rgba(255,255,255,0) 60%);
  transform:translateX(-135%);
}
/* The drawer is moved off screen with a transform rather than display:none, so
   an unconditional animation would repaint for the life of the page. */
@media (prefers-reduced-motion:no-preference){
  .dp-sold::after{animation:badge-glint 4.5s ease-in-out 1s infinite;animation-play-state:paused}
  .drawer.on .dp-sold::after{animation-play-state:running}
}

/* ============================================================
   "Most popular" and "Best value".
   These two flags do more work than anything else in the grid —
   they are the only thing telling a first-time buyer which box to
   pick. Gold foil, a heavier cut, and a glint that runs once the
   ladder is on screen.
   ============================================================ */
.t-rec{
  position:absolute;top:-12px;z-index:3;overflow:hidden;
  padding:4px 13px;border-radius:var(--r-pill);
  font-family:var(--ui);font-weight:900;letter-spacing:.03em;
  color:var(--ink);
  background:
    linear-gradient(158deg,
      #FFEEB4 0%, #FBD35C 15%, var(--gold) 33%,
      #E9B222 52%, #FFDD6B 70%, #F0BA2C 86%, #E3A917 100%);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.65),
    inset 0 -1px 0 rgba(120,79,0,.3),
    0 4px 12px -2px rgba(0,0,0,.45);
  text-shadow:0 1px 0 rgba(255,255,255,.35);
}
/* Best value reads as the quieter of the two: same foil, cooler edge, so the
   default choice still wins the eye. */
.t-rec--value{
  background:
    linear-gradient(158deg,
      #FFF6D8 0%, #FFE9A6 18%, var(--gold-soft) 38%,
      #F0C64A 56%, #FFF0BE 72%, #FFDC80 88%, #EBC65C 100%);
}
.t-rec::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(104deg,
    rgba(255,255,255,0) 40%, rgba(255,255,255,.85) 48%,
    rgba(255,255,255,.25) 53%, rgba(255,255,255,0) 60%);
  transform:translateX(-135%);
}
@media (prefers-reduced-motion:no-preference){
  .t-rec::after{animation:badge-glint 5.5s ease-in-out 1.6s infinite;animation-play-state:paused}
  /* Only while the buy panel is actually on screen — the same rule the gallery
     flag follows, so the page never animates something nobody is looking at. */
  .buy.in-view .t-rec::after{animation-play-state:running}
  .t-rec{transition:transform .18s cubic-bezier(.2,.9,.3,1)}
  .tier.on .t-rec{transform:translateX(-50%) scale(1.06)}
}

/* ============================================================
   The box picker in the cart.
   A row of durians that fills, and a real range under it. The
   fruit is the explanation — three durians means three durians —
   so the numbers underneath can stay quiet.
   ============================================================ */

/* per fruit leads the cart line, as it does on the buy cards */
.line-amt{display:flex;flex-direction:column;align-items:flex-end;gap:2px;text-align:right}
.line-amt b{
  display:block;font-family:var(--dsp);font-variation-settings:'wdth' 92,'opsz' 40;
  font-size:1.4375rem;font-weight:800;letter-spacing:-.04em;line-height:1.1;color:var(--ice);
  font-variant-numeric:tabular-nums;white-space:nowrap;
}
.line-amt span{
  display:block;font-family:var(--ui);font-size:0.78125rem;font-weight:700;
  color:var(--mist);white-space:nowrap;letter-spacing:0;
}

/* the durians you are getting */
.sv-fruit{
  display:flex;align-items:flex-end;justify-content:center;
  gap:clamp(5px,1.2vw,10px);margin:clamp(3px,1svh,11px) 0 0;min-height:0;
}
/* The sprite durian is square; the raster one it replaces was portrait, and
   carrying that ratio over squashed the illustration into a fuzzy ball. */
.sv-fruit .fr{
  display:block;height:clamp(24px,4.9svh,48px);width:auto;aspect-ratio:1;
  flex:0 0 auto;opacity:.2;filter:grayscale(1);
}
.sv-fruit .on{opacity:1;filter:none}
@media (prefers-reduced-motion:no-preference){
  .sv-fruit .fr{
    transition:opacity .2s ease, filter .2s ease, transform .22s cubic-bezier(.2,.9,.3,1);
  }
  .sv-fruit .on{transform:translateY(-2px)}
}

/* the control: six numbers, and they look like six numbers.
   A segmented group rather than a slider — it needs no affordance cue, every
   stop is a 44px target, and it is the control an older thumb already knows. */
.sv-segs{
  display:grid;grid-auto-flow:column;grid-auto-columns:1fr;margin:clamp(4px,1.2svh,13px) 0 0;
  border:1.5px solid var(--gold);border-radius:12px;overflow:hidden;
  background:rgba(8,38,27,.4);
}
.sv-segs button{
  min-height:clamp(44px,6svh,56px);padding:0 2px;cursor:pointer;border:0;
  border-right:1px solid rgba(245,193,54,.35);background:none;color:var(--ice);
  font-family:var(--ui);font-size:clamp(1rem,2.1svh,1.125rem);font-weight:800;line-height:1;
  font-variant-numeric:tabular-nums;
}
.sv-segs button:last-child{border-right:0}
.sv-segs button[aria-pressed="true"]{background:var(--gold);color:var(--ink)}
.sv-segs button:focus-visible{outline:3px solid var(--ice);outline-offset:-3px}
@media (prefers-reduced-motion:no-preference){
  .sv-segs button{transition:background .13s ease,color .13s ease}
}
@media (max-width:359px){
  .sv-segs button{font-size:0.90625rem;min-height:42px}
}

.sv-live{
  margin:6px 0 0;text-align:center;
  font-family:var(--ui);font-size:0.8125rem;font-weight:700;color:var(--mist);
}
.dr-save.maxed .sv-live{color:var(--gold-soft)}

@media (max-width:359px){
  .sv-fruit{gap:3px}
  .sv-fruit .fr{height:32px}
  .sv-live{font-size:0.75rem}
}

/* the live line duplicated the cart row above it; the fruit already counts */
.sv-live{display:none}

/* ============================================================
   The step rail.
   Three named steps with the current one lit, so a shopper always
   knows how far in they are and how much is left. Step 3 is
   Shopify's own checkout and the rail cannot follow them there —
   naming it is what says only one step remains.
   ============================================================ */
/* --------------------------------------------------------------- title ---
   The rating reads as one line — score, count, units shipped — and the claims
   under the name are four ticks rather than a sentence and a spec pill. Each
   line is one thing a shopper can accept or reject on its own, which is how
   they are actually read on a phone. */
.rating .r-avg{
  font-family:var(--ui);font-size:0.96875rem;font-weight:800;letter-spacing:-.01em;
  color:var(--ice);font-variant-numeric:tabular-nums;
}
.h-list{list-style:none;margin:13px 0 0;padding:0;display:flex;flex-direction:column;gap:9px}
.h-list li{
  display:flex;align-items:center;gap:11px;min-width:0;
  font-family:var(--ui);font-size:clamp(0.90625rem,4vw,1.03125rem);font-weight:600;
  line-height:1.3;color:var(--ice);
}
html[lang^="zh"] .h-list li{font-family:var(--cjk),var(--ui)}
.h-tick{
  flex:0 0 auto;display:grid;place-items:center;width:26px;height:26px;
  border-radius:50%;background:rgba(245,193,54,.15);
  border:1px solid rgba(245,193,54,.42);color:var(--gold);
}
.h-tick svg{width:13px;height:13px;display:block;fill:none;stroke:currentColor;
  stroke-width:2.6;stroke-linecap:round;stroke-linejoin:round}
@media (max-width:359px){
  .h-list{gap:8px}
  .h-list li{font-size:0.84375rem;gap:9px}
  .h-tick{width:23px;height:23px}
  .h-tick svg{width:12px;height:12px}
}

/* --------------------------------------------------------------- steps ---
   Words, not icons. Three labelled stops with their own pictures asked the
   shopper to read a map of the checkout before they had read the product.
   "Step 1 of 3" and the screen's own title say it in a line, the dashes carry
   the position without asking to be read, and the fruit runs off the edge so
   the band reads as a piece of the product rather than a progress widget. */
.dg-step{
  position:relative;overflow:hidden;
  display:flex;align-items:center;justify-content:space-between;gap:10px;
  margin:0 0 12px;padding:14px 0 14px 16px;border-radius:20px;
  background:linear-gradient(150deg,#1A6644 0%,#123F2C 58%,#0D3021 100%);
  border:1px solid rgba(234,244,238,.09);
}
.ds-copy{min-width:0;flex:1 1 auto}
/* Step and position on one line: neither needs a row of its own. */
.ds-top{display:flex;align-items:center;gap:11px}
.ds-eye{
  font-family:var(--ui);font-size:0.875rem;font-weight:800;
  letter-spacing:.15em;text-transform:uppercase;color:var(--gold);white-space:nowrap;
}
html[lang^="zh"] .ds-eye{letter-spacing:.06em;font-size:0.84375rem;font-family:var(--cjk),var(--ui)}
.ds-dots{display:flex;align-items:center;gap:5px;flex:0 0 auto}
.ds-dots i{display:block;width:20px;height:6px;border-radius:99px;background:rgba(234,244,238,.17)}
.ds-dots i.done{background:rgba(245,193,54,.45)}
.ds-dots i.on{background:var(--gold);box-shadow:0 0 9px rgba(245,193,54,.45)}
.ds-title{
  display:block;margin-top:7px;
  font-family:var(--dsp);font-variation-settings:'wdth' 92,'opsz' 40;
  font-size:clamp(1.4375rem,6.2vw,1.875rem);font-weight:800;letter-spacing:-.035em;
  line-height:1.02;color:var(--ice);
}
html[lang^="zh"] .ds-title{font-family:var(--cjk),var(--dsp);letter-spacing:0}
.ds-lede{
  display:block;margin-top:5px;font-family:var(--ui);
  font-size:clamp(0.84375rem,3.7vw,0.96875rem);font-weight:600;line-height:1.3;color:var(--mist);
}
.ds-hero{flex:0 0 auto;align-self:stretch;display:flex;align-items:center;margin:-14px 0}
.ds-hero img{
  display:block;height:clamp(104px,30vw,140px);width:auto;
  margin-right:-14px;filter:drop-shadow(0 8px 16px rgba(0,0,0,.42));
}
@media (max-width:359px){
  .dg-step{padding:12px 0 12px 13px}
  .ds-top{gap:8px}
  .ds-dots i{width:16px;height:5px}
}

/* The cart's band is the fold's band — .dg-step carries the whole look, and
   nothing here repeats it. The header above is now only a toolbar: a back
   button and the language pill, with the band as its own block underneath.

   What is set here is size, not style. The fold sizes itself against viewport
   width, which is right for a page that scrolls; this panel is fighting for
   height and has to fit one screen, so its band scales against svh instead —
   the same band, smaller on a small phone rather than pushing the checkout
   button off the bottom. */
/* The header is two controls now, not a title bar, so it is sized like two
   controls. Every pixel it gives back is a pixel the band costs the panel. */
/* The band is a grid so its top line can span the full width while the fruit
   keeps the right of the rows beneath it. As a flex row the back button and the
   pill had to share a line with the fruit, which is what forced them out into a
   bar of their own in the first place. */
.drawer .dr-step{
  /* The sheet is a height-capped flex column, so every child is shrinkable by
     default — which is why the band's own grid measured 175px and the element
     rendered 132, clipping its title and lede against overflow:hidden. Only the
     body scrolls; the band and the footer keep the height they ask for. */
  flex:0 0 auto;
  display:grid;align-items:end;
  grid-template-columns:minmax(0,1fr) auto;
  grid-template-areas:"bar bar" "copy hero";
  gap:0 10px;
  margin:clamp(6px,1.2svh,12px) 14px clamp(6px,1.3svh,12px);
  padding:clamp(7px,1.2svh,11px) 0 clamp(9px,1.6svh,14px) 14px;
}
.drawer .dr-step .ds-bar{
  grid-area:bar;display:flex;align-items:center;gap:10px;
  padding-right:12px;margin-bottom:clamp(2px,.6svh,7px);
}
.drawer .dr-step .ds-copy{grid-area:copy;min-width:0}
/* The fold's fruit hangs on negative block margins, which is right in a flex
   row and wrong in a grid: the row then measures 28px shorter than the image
   in it, and everything in the band overflowed the rounded box and was clipped.
   Here the margins are cleared, the row measures honestly, and the bleed is a
   small deliberate overhang instead. */
.drawer .dr-step .ds-hero{grid-area:hero;align-self:end;margin:0;overflow:visible}
.drawer .dr-step .ds-hero img{
  height:clamp(58px,9.4svh,88px);margin:0 -12px -8px 0;
}
/* The step label takes the middle so the two controls sit at the band's edges. */
.drawer .dr-step .ds-top{flex:1 1 auto;min-width:0}
.drawer .dr-step .dr-back{
  flex:0 0 auto;width:clamp(30px,4.2svh,36px);height:clamp(30px,4.2svh,36px);
}
.drawer .dr-step .dr-back svg{width:12px;height:9px}
.drawer .dr-step .dr-lang{flex:0 0 auto}
.drawer .dr-step .dl-btn{height:clamp(28px,4svh,34px);padding:0 10px;font-size:0.78125rem}
.drawer .dr-step .ds-title{font-size:clamp(1.1875rem,3.3svh,1.875rem)}
.drawer .dr-step .ds-lede{font-size:clamp(0.75rem,1.8svh,0.96875rem);margin-top:clamp(2px,.5svh,5px)}
.drawer .dr-step .ds-dots i{width:clamp(14px,2.6svh,20px)}
/* An empty cart has no box to describe and no step to be on. */
/* The empty cart used to hide this whole band — which took the close control
   with it. openDrawer focuses #drx on open, so on an empty cart focus went to
   a display:none button and the only way out of a full-screen panel was to
   guess that tapping the dimmed page would close it. The band stays; the
   fruit-count lede under the title is what goes, because there is no fruit to
   count. */
.drawer.empty .dr-step .ds-lede{display:none}


/* A quiet heading over each part, so the panel reads as sections rather than
   a stack of cards. */
.dr-sec{
  margin:14px 0 7px;font-family:var(--ui);font-size:0.71875rem;font-weight:800;
  letter-spacing:.14em;text-transform:uppercase;color:var(--mist);
}
html[lang^="zh"] .dr-sec{letter-spacing:.04em;text-transform:none;font-size:0.8125rem;
  font-family:var(--cjk),var(--ui)}
html[lang="vi"] .dr-sec{letter-spacing:.06em;text-transform:none;font-size:0.78125rem}

/* With the sheet claiming the screen there is room to breathe between parts. */
@media (min-height:700px){
  .dr-body{padding:0 18px 12px}
  .dr-save{margin-top:13px}
}



/* ============================================================ origin ======
   Where the fruit is grown and how it is picked, built from the theme's own
   tokens rather than a second palette — the reference this follows used its
   own greens and golds, and carrying those in would have left the page with
   two nearly-identical sets of the same colours drifting apart over time.

   The section is its own file, so these are the only rules that describe it
   and nothing above can reach in. Every measure is a clamp: the same layout
   holds from a 4.7-inch phone to a wide desktop without a breakpoint per size.
   ------------------------------------------------------------------------ */
.org{display:block;background:var(--abyss);color:var(--ice)}
.org-in{max-width:1080px;margin:0 auto;padding:0 20px}

/* ---- hero: photograph, then the claim over the bottom of it ---- */
.org-hero{
  position:relative;display:flex;align-items:flex-end;overflow:hidden;
  min-height:clamp(430px,72vh,620px);
}
.org-hero-img{position:absolute;inset:0}
.org-hero-img img{display:block;width:100%;height:100%;object-fit:cover}
/* The scrim is the reason the type is readable at all: it has to reach full
   ground colour at the bottom or the section below starts on a seam. */
.org-hero-img::after{
  content:"";position:absolute;inset:0;
  background:linear-gradient(to bottom,
    rgba(9,32,23,.45) 0%, rgba(9,32,23,.14) 35%,
    rgba(14,66,48,.88) 82%, var(--abyss) 100%);
}
.org-hero-copy{
  position:relative;width:100%;max-width:1080px;margin:0 auto;
  padding:0 20px clamp(30px,6vw,46px);
}
.org-eye{
  display:inline-block;margin:0 0 13px;font-family:var(--ui);
  font-size:0.8125rem;font-weight:800;letter-spacing:.19em;text-transform:uppercase;
  color:var(--gold);
}
html[lang^="zh"] .org-eye,html[lang="vi"] .org-eye{letter-spacing:.05em;text-transform:none;font-size:0.875rem}
.org-h1{
  margin:0;font-size:clamp(2.125rem,8.5vw,4rem);font-weight:800;
  line-height:1.03;letter-spacing:-.04em;color:var(--ice);
  text-shadow:0 2px 30px rgba(9,32,23,.5);
}
.org-h1 span,.org-h1 em{font-style:normal}
/* The region is the line's own line — it is the specific thing being claimed. */
.org-h1 em{display:block;color:var(--gold)}
html[lang^="zh"] .org-h1{font-family:var(--cjk),var(--dsp);letter-spacing:0;line-height:1.2}
.org-kicker{
  margin:15px 0 0;max-width:34ch;font-family:var(--ui);
  font-size:clamp(1rem,4.3vw,1.25rem);font-weight:500;line-height:1.5;color:#E4EDE5;
}

/* ---- intro ---- */
/* The hero's own copy already ends on 30-46px of padding inside the
   photograph, so this stacked on top of that and the two together left up to
   110px of empty green between the kicker and the line it sets up. */
.org-intro{padding:clamp(18px,3.4vw,30px) 20px clamp(10px,3vw,20px)}
.org-lead{
  margin:0;font-size:clamp(1.25rem,5.4vw,1.875rem);font-weight:800;
  line-height:1.28;letter-spacing:-.03em;color:var(--ice);max-width:24ch;
}
html[lang^="zh"] .org-lead{font-family:var(--cjk),var(--dsp);letter-spacing:0}
.org-body{
  margin:16px 0 0;font-family:var(--ui);
  font-size:clamp(0.96875rem,4.1vw,1.125rem);font-weight:500;line-height:1.55;
  color:var(--mist);max-width:46ch;
}

/* ---- the three reasons ---- */
.org-reasons{display:grid;gap:12px;padding-top:clamp(24px,5vw,44px);padding-bottom:clamp(24px,5vw,44px)}
.org-card{
  background:var(--jade);border:1px solid var(--glass-line);
  border-radius:20px;padding:clamp(18px,4.5vw,26px);
}
.org-ic{
  display:grid;place-items:center;width:44px;height:44px;border-radius:50%;
  background:rgba(245,193,54,.16);color:var(--gold);margin-bottom:14px;
}
.org-ic svg{width:22px;height:22px;display:block}
.org-card h3{
  margin:0 0 7px;font-family:var(--ui);
  font-size:clamp(1.125rem,4.6vw,1.3125rem);font-weight:800;letter-spacing:-.02em;color:var(--ice);
}
.org-card p{
  margin:0;font-family:var(--ui);
  font-size:clamp(0.9375rem,4vw,1.03125rem);font-weight:500;line-height:1.55;color:var(--mist);
}

/* ---- picking: photo above copy, two up once there is room ---- */
.org-split{display:grid;gap:14px;padding-bottom:clamp(30px,6vw,52px)}
.org-panel{
  background:var(--jade);border:1px solid var(--glass-line);
  border-radius:22px;overflow:hidden;
}
.org-ph{aspect-ratio:4/5;overflow:hidden}
.org-ph img{display:block;width:100%;height:100%;object-fit:cover}
.org-pb{padding:clamp(18px,4.5vw,26px)}
.org-step{
  display:inline-block;margin:0 0 10px;font-family:var(--ui);
  font-size:0.78125rem;font-weight:800;letter-spacing:.16em;text-transform:uppercase;color:var(--gold);
}
html[lang^="zh"] .org-step,html[lang="vi"] .org-step{letter-spacing:.04em;text-transform:none;font-size:0.84375rem}
.org-panel h3{
  margin:0 0 8px;font-family:var(--ui);
  font-size:clamp(1.1875rem,5vw,1.4375rem);font-weight:800;letter-spacing:-.025em;line-height:1.16;color:var(--ice);
}
.org-panel p{
  margin:0;font-family:var(--ui);
  font-size:clamp(0.9375rem,4vw,1.03125rem);font-weight:500;line-height:1.55;color:var(--mist);
}

/* ---- the journey ---- */
.org-journey{border-top:1px solid var(--glass-line);padding-top:clamp(30px,6vw,52px);padding-bottom:clamp(30px,6vw,52px)}
.org-h2{
  margin:0 0 clamp(20px,4vw,30px);
  font-size:clamp(1.5rem,6.4vw,2.125rem);font-weight:800;letter-spacing:-.03em;line-height:1.12;color:var(--ice);
}
html[lang^="zh"] .org-h2{font-family:var(--cjk),var(--dsp);letter-spacing:0}
.org-steps{list-style:none;margin:0;padding:0;counter-reset:orgstep;display:grid;gap:0}
.org-steps li{
  display:grid;grid-template-columns:38px 1fr;gap:16px;align-items:start;
  padding:clamp(15px,3.6vw,20px) 0;border-top:1px solid var(--glass-line);
}
.org-steps li:first-child{border-top:0}
.org-steps li::before{
  counter-increment:orgstep;content:counter(orgstep);
  font-family:var(--dsp);font-variation-settings:'wdth' 92,'opsz' 40;
  font-size:clamp(1.25rem,5vw,1.5rem);font-weight:800;letter-spacing:-.03em;
  line-height:1.2;color:var(--gold);font-variant-numeric:tabular-nums;
}
.org-steps h4{
  margin:0 0 4px;font-family:var(--ui);
  font-size:clamp(1.03125rem,4.3vw,1.1875rem);font-weight:800;letter-spacing:-.015em;color:var(--ice);
}
.org-steps p{
  margin:0;font-family:var(--ui);
  font-size:clamp(0.90625rem,3.9vw,1rem);font-weight:500;line-height:1.5;color:var(--mist);
}
.org-free{color:var(--gold);font-weight:800}

/* ---- close ---- */
.org-close{background:var(--jade);padding:clamp(34px,7vw,60px) 0 clamp(40px,8vw,70px)}
.org-close .org-body{margin-top:10px}
.org-promises{list-style:none;margin:24px 0 26px;padding:0;display:grid;gap:10px}
.org-promises li{
  display:flex;gap:11px;align-items:center;font-family:var(--ui);
  font-size:clamp(0.9375rem,4vw,1.0625rem);font-weight:600;color:var(--ice);
}
.org-tick{flex:0 0 auto;display:grid;place-items:center;color:var(--gold)}
.org-tick svg{width:20px;height:20px;display:block}
.org-cta{
  display:inline-flex;align-items:center;justify-content:center;gap:9px;
  min-height:60px;padding:0 32px;border-radius:999px;
  background:var(--gold);color:var(--abyss);text-decoration:none;
  font-family:var(--ui);font-size:clamp(1.0625rem,4.4vw,1.1875rem);font-weight:800;letter-spacing:-.015em;
  box-shadow:0 10px 26px rgba(0,0,0,.28);
  transition:transform .15s ease;
}
.org-cta:hover{transform:translateY(-2px)}
.org-cta:focus-visible{outline:3px solid var(--gold);outline-offset:3px}

@media (min-width:760px){
  .org-reasons{grid-template-columns:repeat(3,1fr);gap:16px}
  .org-split{grid-template-columns:1fr 1fr;gap:18px}
  .org-steps{grid-template-columns:repeat(2,1fr);column-gap:40px}
  /* Two columns means row two starts a column, so it owns no rule either. */
  .org-steps li:nth-child(2){border-top:0}
  .org-intro{display:grid;grid-template-columns:1fr 1fr;gap:40px;align-items:start}
  .org-lead{max-width:none}
  .org-body{margin-top:6px}
}
@media (prefers-reduced-motion:reduce){
  .org-cta{transition:none}
  .org-cta:hover{transform:none}
}


/* ------------------------------------------------- the per-fruit price ----
   The figure that answers "is this a good price". It is what moves when the
   stepper moves and the only number a shopper can carry to another shop and
   compare, so it is read first: the ladder's single-fruit rate struck beside
   it, the unit named underneath, and the line total labelled so the two
   figures cannot be mistaken for each other. */
.drawer .line-each{
  /* Pushed to the row's right edge and set flush right, so it stacks over the
     line total beneath it.

     A block, not a wrapping flex row: as a flex container the full-width label
     and the auto width fed each other and the column resolved to 174px, which
     squeezed "Musang King Durian" onto three lines. As a block it is simply as
     wide as its widest line. */
  flex:0 0 auto;margin:0 0 0 auto;padding-left:12px;
  display:block;text-align:right;white-space:nowrap;
}
.drawer .line-each .le-lbl{display:block;text-align:right;margin-top:4px}
/* The total is the large figure here too. It used to be the rate; the picker
   now leads with the total, and a cart that led with a different number would
   be asking the shopper to re-read the decision they just made. */
.drawer .line-each em{
  font-style:normal;font-family:var(--dsp);font-variation-settings:'wdth' 92,'opsz' 40;
  font-size:clamp(1.4375rem,3.8svh,1.8125rem);font-weight:800;letter-spacing:-.035em;
  line-height:1;color:var(--ice);font-variant-numeric:tabular-nums;
}
.drawer .line-each .le-lbl{
  font-style:normal;font-family:var(--ui);
  font-size:clamp(0.65625rem,1.6svh,0.75rem);font-weight:800;
  letter-spacing:.14em;text-transform:uppercase;color:var(--mist);margin-top:4px;
}
html[lang^="zh"] .drawer .line-each .le-lbl,html[lang="vi"] .drawer .line-each .le-lbl{
  letter-spacing:.04em;text-transform:none;font-size:clamp(0.71875rem,1.7svh,0.8125rem);
}
/* The line total is now a named, secondary figure beside the stepper. */
/* The rate, beside the stepper. Gold, because it is the number that changes
   when the stepper moves — that movement is the reason to step up.

   It wraps to two right-aligned lines rather than running on: with the struck
   rate beside it the pair needs ~144px, and the row has the stepper and Remove
   to its left, so on one line it ran 9px past the card's edge and was clipped.
   nowrap belongs on each figure, not on the box holding them. */
.drawer .line-amt{
  display:flex;flex-wrap:wrap;justify-content:flex-end;align-items:baseline;
  gap:0 7px;margin-left:auto;min-width:0;text-align:right;white-space:normal;
  font-family:var(--ui);font-size:clamp(0.8125rem,2svh,0.9375rem);font-weight:700;
  color:var(--mist);line-height:1.3;
}
.drawer .line-amt b,.drawer .line-amt s{white-space:nowrap}
/* The size and the face have to be restated, not just the weight and the
   colour. There is a .line-amt b higher up the file — written for the cart
   page, where the rate is the headline figure — that sets 23px in the display
   face. It carries an element on top of its class, the container's own
   font-size cannot reach a child that declares its own, and this rule used to
   set only font-weight and colour. So the gold rate rendered at 23px display
   beside a 14px struck figure: larger than the box title above it, and wide
   enough that "$11.11 a pound" ran off the right edge of the card. */
.drawer .line-amt b{
  font-family:var(--ui);font-variation-settings:normal;
  font-size:inherit;line-height:inherit;letter-spacing:0;
  font-weight:800;color:var(--gold);
}
.drawer .line-amt s{font-weight:600;opacity:.7;text-decoration-thickness:1.5px}




/* -------------------------------------------- volume, on the step card ----
   The theme's gold-foil badge, sized to sit under the cart count inside the
   band. It keeps the foil and the glint it already had; what is set here is
   only its shape and its place in the copy column, clear of the fruit.

   The figure counts up on first open, so it is given tabular figures — without
   them every frame is a different width and the pill twitches as it runs. */
.drawer .dr-step .ds-sold{
  display:inline-flex;align-items:center;gap:5px;
  margin-top:clamp(4px,.9svh,8px);
  padding:clamp(2px,.5svh,4px) clamp(8px,2vw,11px);border-radius:999px;
  font-family:var(--ui);font-size:clamp(0.6875rem,1.7svh,0.78125rem);line-height:1.3;
  max-width:100%;
}
.drawer .dr-step .ds-sold b{
  font-weight:800;color:var(--ink);font-variant-numeric:tabular-nums;
  font-feature-settings:'tnum' 1;
}
.drawer .dr-step .ds-sold i{
  font-style:normal;font-weight:800;color:var(--ink);opacity:.85;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;
}
/* An empty cart has nothing to be proud of yet. */
.drawer.empty .dr-step .ds-sold{display:none}


/* --------------------------------------------- guarantee, under the CTA ---
   One line, its own mark, centred under the button. The seal is stroked in
   currentColor so it takes the line's colour rather than carrying its own. */
.drawer .dr-guar{
  display:flex;align-items:center;justify-content:center;gap:7px;
  margin:clamp(6px,1.1svh,10px) 0 0;text-align:center;
  font-family:var(--ui);font-size:clamp(0.875rem,2.15svh,0.96875rem);font-weight:700;
  line-height:1.35;color:var(--mist);
}
.drawer .dr-guar .dg-ico{flex:0 0 auto;display:grid;place-items:center;color:var(--gold)}
.drawer .dr-guar .dg-ico svg{width:clamp(16px,2.6svh,19px);height:clamp(16px,2.6svh,19px);display:block}

/* Remove sits at the left of the stepper row, opposite the line total. */
.drawer .line-bot{gap:10px}
.drawer .line-del{
  order:2;margin-left:2px;font-size:clamp(0.75rem,1.9svh,0.84375rem);
}
.drawer .line-step{order:1}
.drawer .line-amt{order:3;margin-left:auto}
.drawer.empty .dr-guar{display:none}


/* ------------------------------------------------------ gallery video ----
   The video slide fills its square exactly as the photographs do, so the track
   snaps identically whichever kind of slide is under the thumb. */
.shot-slide.shot-video{position:relative;overflow:hidden;background:var(--deep)}
.shot-slide.shot-video video,
.shot-slide.shot-video iframe,
.shot-slide.shot-video .video-wrapper{
  display:block;width:100%;height:100%;object-fit:cover;border:0;
}
.shot-slide.shot-video .video-wrapper{position:absolute;inset:0}

/* The thumbnail says it is a film without a word: the still, dimmed, with a
   play mark over it. */
.thumbs .thumb-video{position:relative}
.thumbs .thumb-video img{filter:brightness(.82)}
.thumbs .thumb-video .tv-play{
  position:absolute;inset:0;display:grid;place-items:center;pointer-events:none;color:#fff;
}
.thumbs .thumb-video .tv-play svg{
  width:56%;height:56%;max-width:26px;max-height:26px;display:block;
  filter:drop-shadow(0 1px 3px rgba(0,0,0,.55));
}


/* The range of fruit in the box, under its weight. Quiet by design: the box is
   named by weight because that is what is sold, and the count qualifies it. */
/* What the box holds, and what it weighs. This is the line the shopper is
   actually comparing the three options on, and a good share of the people
   reading it are reading a second language on a phone — so it is set at body
   size in the ice, not as grey caption text under the title. */
/* ---------------------------------------------- sized for older eyes ----
   This shop sells to buyers who are mostly past forty-five, where
   long-sightedness is near-universal. An audit of the live page at 375px
   found twenty-four pieces of visible text under 13.5px and several at nine
   and ten — which is a real share of the customers being asked to squint at
   the terms of a $240 purchase. The sizes below are raised at the rule that
   actually wins on a phone, found by walking the cascade rather than by
   appending overrides: several of these are set in four or five places and a
   blanket override would have pulled the larger breakpoints DOWN. */
.t-cnt{
  display:block;margin-top:3px;font-family:var(--ui);
  font-size:clamp(0.84375rem,3.85vw,0.9375rem);font-weight:700;line-height:1.35;color:var(--ice);
}
html[lang^="zh"] .t-cnt{font-family:var(--cjk),var(--ui)}


/* The chosen box, photographed. The files are cut-outs with a transparent
   ground, so no plate behind them and no fixed ratio to letterbox them into —
   the box simply stands on the card. A soft drop shadow gives it the ground it
   would otherwise be missing. */


/* The box name is set in the product's own display face, not the UI face. It is
   the name of the thing being bought — the same weight the title of the page
   carries — and at body weight in Jakarta it read as another line of interface. */
.t-qty{
  font-family:var(--dsp);font-variation-settings:'wdth' 94,'opsz' 40;
  font-size:clamp(1.09375rem,4.7vw,1.25rem);font-weight:800;letter-spacing:-.025em;
}
html[lang^="zh"] .t-qty{font-family:var(--cjk),var(--dsp);letter-spacing:0}


/* ------------------------------------------- the opened option, compact ----
   Photo and perks side by side. Stacked, the panel ran about 280px — the
   photograph alone was 217 — so opening one box pushed the other two off the
   screen at exactly the moment the shopper wanted to compare them. Beside each
   other the whole thing is roughly a third of that.

   The photo takes a fixed share rather than its natural size: it is there to
   confirm what arrives, not to be the hero. The perks are the hero. */
/* The .t-shot rules that stood here sized a box photograph that the panel no
   longer renders. Removed with it rather than left behind: a rule for an
   element that cannot appear is the kind of thing that gets "fixed" later by
   someone who assumes the element is missing by mistake. */

/* Three single lines, each one claim, stacked in the space beside the box. */
.t-pico{
  flex:0 0 auto;display:grid;place-items:center;
  width:26px;height:26px;border-radius:50%;
  background:rgba(245,193,54,.15);color:var(--gold);
}
.t-pico svg{width:14px;height:14px;display:block;fill:currentColor}" — the panel is hidden until its option
   is chosen by ".buy .tier.on .t-r2", and a same-specificity rule written later
   in the file un-hid it, so every box showed its perks at once. Only the inner
   row is laid out here; whether the panel shows at all is left alone. */

@media (max-width:359px){
  .t-pico{width:23px;height:23px}
  .t-pico svg{width:12px;height:12px}
}


/* ------------------------------------------------ phone and the office ----
   A number to ring and an address to look up. Both are plain facts a shopper
   can check, which is the whole reason they build trust — so they are stated
   quietly and legibly rather than decorated. */
/* Inline, not flex: the number and the sentence are one run of text, so the
   sentence wraps back to the left edge under the number the way it reads in
   the design. As flex columns the tail became its own block and hung off the
   number's right edge instead. */
.as-tel .as-call{display:inline;color:inherit;text-decoration:none}
.as-tel .as-call b{
  font-family:var(--ui);font-size:inherit;font-weight:800;color:var(--ice);
  letter-spacing:-.01em;white-space:nowrap;
}
.as-tel .as-call i{font-style:normal;color:var(--mist)}
.as-tel .as-call span{font-family:var(--ui);font-weight:600;color:var(--mist)}
.as-tel .as-call:hover b{color:var(--gold)}
.as-tel .as-call:focus-visible{outline:2px solid var(--gold);outline-offset:3px;border-radius:6px}

/* The footer's call link matches its email link, so the pair reads as one row
   of ways to reach a person rather than as two different components. */
.foot-tel .foot-call-n{font-variant-numeric:tabular-nums}

.foot-addr{
  display:block;margin:14px 0 0;font-style:normal;font-family:var(--ui);
}
.foot-addr-l{
  display:block;font-size:0.6875rem;font-weight:800;letter-spacing:.14em;
  text-transform:uppercase;color:rgba(234,244,238,.5);
}
html[lang^="zh"] .foot-addr-l,html[lang="vi"] .foot-addr-l{
  letter-spacing:.04em;text-transform:none;font-size:0.78125rem;
}
.foot-addr-n{
  display:block;margin-top:4px;font-size:0.90625rem;font-weight:600;
  line-height:1.45;color:var(--ice);
}


/* ------------------------------------------ the rate, under the total ----
   Both money figures on one right-hand edge. */
.t-rate{
  display:block;margin-top:5px;font-style:normal;font-family:var(--ui);
  font-size:clamp(0.875rem,3.8vw,0.96875rem);font-weight:800;letter-spacing:-.01em;
  color:var(--gold);font-variant-numeric:tabular-nums;white-space:nowrap;
}
html[lang^="zh"] .t-rate{font-family:var(--cjk),var(--ui);letter-spacing:0}

/* ---------------------------------------------- perks, as check marks ----
   Four claims where three sat before, so they are set smaller and the icon
   discs are gone: a 26px disc per line is 104px of the panel spent on
   decoration. A check mark costs a character and says the same thing.

   The glyph is named in the escaped form rather than pasted in, so the file
   survives a re-save under a different encoding, and the font stack is stated
   on the marker itself: on a Chinese page the body font is the CJK face, and
   its check is a wider, heavier glyph that would not sit level with the three
   Latin lines around it. */
/* Raised from 11.5–12.5px. These four lines are the whole trust case — grade,
   hand-picked, free shipping, guarantee — and they were the smallest readable
   thing on the page for an audience that is mostly past forty-five. They were
   shrunk deliberately once, to stop the open panel stretching; the panel is
   allowed to be a little taller than that if the alternative is a customer who
   cannot read what they are being promised.

   This is the third .t-perk b rule in the file and the one that wins. The two
   above it are earlier and were left alone: the size a phone actually gets is
   settled here. */


/* ============================================================
   Reachable and readable in the cart
   ============================================================
   An audit of the drawer at 4.7in found the controls a shopper uses to change
   their mind were the smallest things on it: Remove was 16px tall, the
   stepper 34, the back arrow and the language pill under 30. Every one of
   them is below the 44px a fingertip needs, on the panel where an older
   shopper is most likely to be correcting something.

   Where growing a control would push the panel taller — the stepper, which
   sets the pill height — the padding is negative-margined back out, so the
   target grows and the layout does not. Appended and scoped past what they
   override, because several of these are set two and three times in this file
   and the last rule is the one that counts.
   ============================================================ */

/* Remove was 16px tall and 12.7px of text — the control for undoing a
   mistake, and the hardest thing on the panel to hit. */
.drawer .line-del{
  display:inline-flex;align-items:center;min-height:44px;
  padding:14px 8px;margin:-14px -8px;
  font-size:0.875rem;
}

/* Back, and the language pill beside it. */
.drawer .dr-back{width:40px;height:40px}
.drawer .dr-lang .dl-btn{min-height:40px;padding:0 14px}

/* The stepper. 40px keeps the pill at the height it already is while giving
   the buttons six more pixels each. */
.drawer .line-step .ls-b{width:44px;height:40px}

/* "Total" beside the line price was 10.7px — the smallest text in the cart,
   labelling the largest number in it. */
.drawer .line-each .le-lbl{font-size:0.75rem}

/* The saving is the reason to feel good about the total, and it was set
   smaller than the row labels around it. */
.drawer .dr-tot .dt-save{font-size:0.90625rem}

/* What is in the box, on the panel that says what is in the box. */
.drawer .dr-step .ds-lede{font-size:clamp(0.84375rem,2svh,0.96875rem)}


/* The arrival date in the buy panel, in the assurance card under the rule it
   answers. Same row shape as the lines around it; the date itself is set in
   ice so the eye lands on the day. */
.assure .as-eta[hidden]{display:none}
.assure .as-eta .as-tx b{color:var(--ice);font-weight:800}


/* ---------------------------------------------- the delivery row ----
   Left-aligned. There are two .dr-eta rules in this file and the later one
   centred the whole row, so the date sat in the middle of a card whose other
   rows all start at the same left edge — the eye had to find it each time.

   The mark is the circle used by the assurance block above the cart, at the
   same size and weight, because they are the same kind of thing: a small
   icon standing for one promise. It was a bare 24px glyph, which read as
   decoration rather than as a calendar.

   And the date wraps rather than truncating. The old rule set nowrap with an
   ellipsis, which on a narrow phone would have cut the one thing the row
   exists to say. */
.drawer .dr-eta{justify-content:flex-start;text-align:left;gap:13px}
.drawer .dr-eta .de-ico{
  width:42px;height:42px;padding:10px;border-radius:50%;
  border:1.5px solid rgba(255,201,77,.5);color:var(--gold);
}
.drawer .dr-eta .de-copy{text-align:left}
.drawer .dr-eta .de-copy b{
  white-space:normal;overflow:visible;text-overflow:clip;
  font-size:clamp(0.9375rem,2.3svh,1.0625rem);line-height:1.25;
}
.drawer .dr-eta .de-copy i{font-size:clamp(0.875rem,2.1svh,0.96875rem)}


/* The last two from the readability sweep.

   "TOTAL" under each price was 11.5px — the smallest label on the buy panel,
   sitting under its largest number. And Shopify's own "More payment options"
   arrives at 38px, four short of a fingertip; it is their markup but the
   padding is ours to set. */
.t-perlbl{font-size:0.78125rem}
.dg-express .shopify-payment-button__more-options{min-height:44px}
.drawer .line-each .le-lbl{font-size:0.78125rem}


/* --------------------------------------------- the delivery row, tidied ----
   The struck price and the FREE badge were two floating things competing with
   the text for a 260px card. They are one pill now — "$54 FREE" reads as a
   single fact, and it stops the date being squeezed into three lines.

   This block used to hold both lines to one line each and ellipse the
   overflow, on the reasoning that the date is short enough to fit at every
   size the card takes. Measured, it is not. On a 390px phone the date filled
   180px of a 180px column — nothing in hand — and the theme shipped truncated
   on a real device: "Arrives Tuesday, 9 ..." over "Ships Monday · overnig...".

   Two things ate the margin that was assumed to be there. The mark is 42px
   until the viewport drops under 720px, so a tall phone got the wide one; and
   9/1 is the shortest date of the year. "Arrives Wednesday, 12/25" needs 216px
   at this size and was never going to fit on one line at any icon width.

   So the row no longer truncates. It wraps, which is the only way it can keep
   its promise of saying when the box arrives, and everything around the words
   gives up a little room so that wrapping stays rare: the mark comes down to
   36px, the gap to 10, the pill's side padding to 10, and each line drops one
   step of type. The date now has 196px, and only the longest weekday-plus-date
   in the calendar takes a second line.

   Note the two rules 30 lines above this one, which set white-space:normal on
   the same elements and lost to these on source order alone. They are the
   reason the comment up there says the date wraps while the theme ellipsed it.
   Both now agree. */
.drawer .dr-eta{gap:10px;padding:11px 12px}
.drawer .dr-eta .de-ico{width:36px;height:36px;padding:8px}
.drawer .dr-eta .de-copy b{
  white-space:normal;overflow:visible;text-overflow:clip;
  font-size:clamp(0.9375rem,2.3svh,1rem);line-height:1.22;
}
.drawer .dr-eta .de-copy i{
  white-space:normal;overflow:visible;text-overflow:clip;
  margin-top:1px;font-size:clamp(0.75rem,1.85svh,0.8125rem);line-height:1.25;
}
.drawer .dr-eta .de-free{
  display:inline-flex;align-items:baseline;gap:5px;
  padding:6px 10px;white-space:nowrap;
}
.drawer .dr-eta .de-free .de-was{
  font-size:0.84375rem;font-weight:700;color:var(--ink);opacity:.5;
  text-decoration:line-through;text-decoration-thickness:1.5px;
}
.drawer .dr-eta .de-free em{font-style:normal;font-weight:800}


/* ------------------------------------- the arrival date, on the buy panel ----
   Centred against its mark. The rows in this card are set to flex-start
   because most of them run to two or three lines and want their icon beside
   the first one — this row is a single line, so top-alignment left the text
   riding above the circle.

   Gold and heavy, because it is the answer to the question the whole card is
   about, and it was set in the same muted grey as the sentence explaining the
   rule above it. */
.assure .as-eta{align-items:center}
.assure .as-eta .as-tx{
  color:var(--gold);font-weight:800;
  font-size:clamp(0.96875rem,4.1vw,1.03125rem);letter-spacing:-.005em;
}
.assure .as-eta .as-tx b{color:var(--gold);font-weight:800}
.assure .as-eta .as-ic{border-color:rgba(255,201,77,.75)}

/* It arrives rather than appearing: the date is filled in by script a moment
   after the card paints, and a line that simply materialises reads as a
   glitch. The ring then breathes slowly — slow enough to notice only if you
   look at it, which is the point. A shopper who has asked for less motion
   gets the date without either. */
@keyframes dg-eta-in{from{opacity:0;transform:translateY(5px)}to{opacity:1;transform:none}}
@keyframes dg-eta-ring{
  0%,100%{box-shadow:0 0 0 0 rgba(245,193,54,0)}
  50%{box-shadow:0 0 0 6px rgba(245,193,54,.12)}
}
@media (prefers-reduced-motion:no-preference){
  .assure .as-eta:not([hidden]){animation:dg-eta-in .42s cubic-bezier(.2,.75,.25,1) both}
  .assure .as-eta .as-ic{animation:dg-eta-ring 2.8s ease-in-out infinite}
}


/* ============================================================
   Section bands
   ============================================================
   Nine sections, three thousand pixels, and — apart from the cream how-to
   panel and the taste block — all of it on one green. A reader scrolling had
   almost no landmarks to navigate by, and a reader who left and came back had
   no way to find where they were.

   The page already made two of these calls, and both were right, so this
   builds on them rather than over them: the cream instructional panel is the
   strongest break on the page and it stays exactly as it is (its type is set
   in near-black — painting it dark would have made it unreadable), and taste
   was already a step down into --deep.

   What was missing was everything after it. Origin, questions and reviews all
   sat on the page's own green, so the bottom two-thirds read as one
   undifferentiated field. Completing the rhythm:

           fold + buy    abyss   the decision, on the page's own ground
           how it tastes deep    a step down; photography reads better dark
           nutrition     abyss   back up — a data panel
           how to open   CREAM   the light break, already there
           origin        ink     darkest; the story, and the end of the selling
           questions     abyss
           reviews       deep
           footer        ink

   Hairlines go only between two dark bands. Cream needs no help marking its
   own edges, and a white hairline on it would be invisible anyway.
   ============================================================ */
.taste-wrap,.taste{background:var(--deep)}
.benefits{background:var(--abyss)}
.org{background:var(--ink)}
.faq-wrap{background:var(--abyss)}
.revs-wrap,.revs{background:var(--deep)}

.taste-wrap,.benefits,.faq-wrap,.revs-wrap{position:relative}
.taste-wrap::before,.benefits::before,.faq-wrap::before,.revs-wrap::before{
  content:"";position:absolute;left:0;right:0;top:0;height:1px;
  background:var(--glass-line);pointer-events:none;
}

/* The bands run edge to edge. .page carries a 50px gutter at desktop, so each
   band pulls out to the viewport and puts the gutter back as padding; at
   mobile, where .page is already flush, both terms resolve to zero. */
.taste-wrap,.benefits,.how-wrap,.org,.faq-wrap,.revs-wrap,.foot{
  margin-left:calc(50% - 50vw);margin-right:calc(50% - 50vw);
  padding-left:max(0px,calc(50vw - 50%));padding-right:max(0px,calc(50vw - 50%));
}
/* Only the band is full-bleed; the FAQ keeps its 820px reading measure,
   centred — left-aligned inside a full-width band reads as a mistake. */
.faq{margin-inline:auto}

/* The footer was --deep, the same green as the reviews band immediately above
   it, so the page ended without ending — reviews and footer read as one long
   block. --ink closes it, and matches the origin band: the two places on the
   page where the selling stops. Its own top hairline already marks the edge. */
.foot{background:var(--ink)}

/* ============================================================
   Cart drawer: taller sheet
   ============================================================
   The sheet was capped at 88svh, then 94svh, and every measurement inside it
   was clamped with a very low floor — head padding down to 6px, body bottom
   padding to 0 — because everything had to fit inside that cap.

   The cap is gone: the drawer is a full-height side panel now, so it has the
   whole viewport. The raised floors below stay, because the point was never
   the extra pixels on their own — it was spending them on spacing a shopper
   can actually read. Every value
   here was edited on the rule that actually wins the cascade — the footer is
   declared three times in this file and only the last one counts. .dr-head is
   declared twice and both are dead: the real header is .dr-step, and .dr-head
   appears in neither the markup nor the JS.

   The type that carries meaning also came up off its floor, now that there is
   room for it: the delivery sub-line, the struck-through shipping price, the
   30-day guarantee and the step eyebrow were all under 14px on a phone. The
   payment-brand marks are left alone — those are rendered wordmarks, not text
   anyone reads.

   Desktop is untouched — at >=900px the drawer is already a full-height side
   panel with max-height:none, so there is nothing to make taller.
   ============================================================ */


/* ============================================================
   Cart drawer: fitting the whole cart on one screen
   ============================================================
   With the panel full-height, the goal became getting everything a shopper
   checks before paying — the line, the free-shipping confirmation, the arrival
   date, the totals, the button and the wallets — onto one screen with nothing
   below the fold.

   Measured with a real cart line at 390x844: the body wanted 456 px and had
   393. These trims close that gap. Every one of them takes chrome, not
   content: the only thing that disappears entirely is the decorative hero
   image in the panel's own header, which is the least useful pixel in a cart.

       header hero image     -32 px   decoration
       header padding        -12 px   chrome
       free-shipping row     -12 px   padding, not words
       arrival row            -8 px   padding, not words
       body gaps / line       -9 px   spacing
       footer top padding     -3 px   chrome

   Honest limit: this fits on a 390x844 phone with no slack left. On a shorter
   screen — an SE at 667 — the body still scrolls, and it should: a cart that
   hides the checkout button to avoid a scrollbar is worse than one that
   scrolls. .dr-body keeps its overflow-y:auto for exactly that case.
   ============================================================ */
.drawer .dr-step .ds-hero{display:none}
.drawer .dr-step{padding-top:8px;padding-bottom:8px}
.drawer .dr-unlock{padding:8px 14px}
.drawer .dr-unlock .ul-copy b{font-size:0.9375rem}
.drawer .dr-eta{padding:8px 11px}
.drawer .dr-tbl{margin-top:7px}
.drawer .dr-body{gap:7px}
.drawer .line{padding-bottom:8px}
.drawer .dr-foot{padding-top:11px}

/* The H1 and rating carried .head's spacing when they lived inside it; on their
   own they need their own. Rating first, tight to the title under it — they are
   one unit, not two stacked blocks. */
/* Title and rating share a row; the sold count has the line under them.

   The rating is deliberately the smaller of the two — 13px stars against a
   28-40px title — because it is corroboration, not the headline. It is also
   allowed to shrink but never to wrap: flex-shrink is off and the whole group
   is nowrap, so on a narrow phone the title reflows around it rather than the
   stars breaking across two lines, which is the one way this row can look
   broken. baseline alignment, so the 4.9 sits on the same line as the first
   line of the title rather than floating against a two-line block. */
.fold-head .fh-top{
  display:flex;align-items:baseline;justify-content:space-between;
  gap:14px;margin:0;
}
/* Two lines, always — "Musang King" on one and "Durian" on the next, which is
   how the markup splits it. The page's global h1 is clamp(28px,7.7vw,40px);
   with the rating now taking 172px off this row, 28px could not fit "Musang
   King" on one line below about 380px and the title broke into three. Measured
   at 360px: 28px gives 3 lines, 25px gives 2. */
.fold-head h1.dsp{margin:0;min-width:0;flex:1 1 auto;font-size:clamp(1.375rem,5.6vw,1.875rem)}
.fold-head .rating{margin:0;flex:0 0 auto;white-space:nowrap}
.fold-head .rating .r-link{gap:5px}
.fold-head .stars svg{width:13px;height:13px}
.fold-head .rating .r-avg{font-size:0.875rem}
.fold-head .r-count{font-size:0.78125rem}

/* Under the title, on its own line. Gold and bold — it is the freshest proof
   on the page and the only number here that is about other buyers rather than
   about the product. */
.fold-head .r-sold{display:block;margin:7px 0 0;font-size:0.875rem}

@media (max-width:409px){
  /* The narrowest phones: drop the word "reviews" to its number and tighten
     the gap, rather than letting the row wrap. */
  .fold-head .fh-top{gap:10px}
  .fold-head .stars svg{width:12px;height:12px}
  .fold-head .r-count{font-size:0.75rem}
}

/* Buy now sits under Add to cart and reads as the quieter of the two: same
   size and same tap target, outlined instead of filled. Two solid gold buttons
   stacked would make the shopper choose between them before choosing a box,
   and adding to the cart is still the path that shows them the arrival date
   and the totals before they commit. */
.cta-buy{
  margin-top:10px;
  background:transparent;color:var(--gold);
  border:1.5px solid var(--gold);box-shadow:none;
}
.cta-buy:hover{background:color-mix(in srgb,var(--gold) 12%,transparent)}
.cta-buy:active{transform:translateY(1px)}

/* Below 360px there is no honest way to keep a 25px title and a full rating on
   one row: the title needs ~140px and the rating ~172px in a 280px line, and
   the only thing that fits both is a 19px title, which is too small to be the
   name of the product. So on those screens the rating goes back under the
   title, which keeps the title at two lines and full width.

   This is a rare case — 320px is an iPhone SE 1 — and it degrades to the
   layout this had before rather than to anything broken. */
@media (max-width:359px){
  .fold-head .fh-top{display:block}
  .fold-head .rating{margin:7px 0 0}
}

/* The crowd numbers, under the title. One line, both linked where it makes
   sense, with the dot doing the separating it used to do up in the rating. */
.fold-head .fh-proof{
  display:flex;align-items:center;flex-wrap:wrap;gap:8px;
  margin:7px 0 0;
}
/* The sold figure in white, not gold. It is a statement of fact about other
   buyers, and gold on this page means money or the thing being sold — the
   price, the savings, the CTA. Ice keeps it legible and stops it competing
   with the figures that are actually asking to be clicked.

   A small gold dot leads it, pulsing slowly, so the line reads as activity
   rather than as another static label.

   The animation is on the dot, not on the number. sold_count is a free-text
   setting — it holds "2.5k" today and the packaged fallback is "50,000+" — so
   counting it up would mean parsing whatever a merchant typed and formatting
   it back, which breaks the first time someone writes "3,000+". A dot cannot
   be typed wrong.

   Slow on purpose: 2.6s, low contrast, no movement of the text itself. This
   sits above the fold on a page whose audience skews older, and a fast or
   loud pulse there is an irritation rather than a signal. */
.fold-head .fh-proof .r-sold{
  margin:0;font-size:0.875rem;color:var(--ice);
  display:inline-flex;align-items:center;gap:9px;
}
.fold-head .fh-proof .r-sold::before{
  content:"";flex:0 0 auto;
  width:7px;height:7px;border-radius:50%;
  background:var(--gold);
}
@media (prefers-reduced-motion:no-preference){
  .fold-head .fh-proof .r-sold::before{
    animation:dg-sold-pulse 2.6s ease-out infinite;
  }
}
/* box-shadow rather than a second element: the ring is drawn outside the dot's
   own 7px box, so nothing in the row shifts as it expands. */
@keyframes dg-sold-pulse{
  0%   {box-shadow:0 0 0 0 rgba(245,193,54,.55)}
  70%  {box-shadow:0 0 0 8px rgba(245,193,54,0)}
  100% {box-shadow:0 0 0 0 rgba(245,193,54,0)}
}
/* The count now rides with the average inside the rating link. */
.fold-head .rating .r-count{
  font-size:0.8125rem;font-weight:600;color:var(--mist);
  font-variant-numeric:tabular-nums;
}

/* ---------- gallery badge ---------- */
/* .shot-slide had no positioning context — it did not need one until now. The
   figure is the containing block so the badge travels with its own slide when
   the rail scrolls, rather than sitting over whatever image is passing. */
.shot-slide{position:relative}
.shot-badge{
  position:absolute;top:12px;left:12px;z-index:2;
  padding:6px 12px;border-radius:var(--r-pill);
  background:var(--gold);color:var(--ink);
  font-family:var(--ui);font-size:0.78125rem;font-weight:800;
  letter-spacing:.08em;text-transform:uppercase;white-space:nowrap;
  /* The photograph behind it is a dark studio shot at the top-left, but a
     merchant can swap in anything, so the badge carries its own separation
     rather than trusting the picture underneath. */
  box-shadow:0 2px 10px -2px rgba(0,0,0,.45);
  pointer-events:none;
}
@media (min-width:900px){
  .shot-badge{top:16px;left:16px;font-size:0.8125rem;padding:7px 14px}
}
html[lang^="zh"] .shot-badge{font-family:var(--cjk),var(--ui);letter-spacing:.04em}
html[lang="vi"] .shot-badge{letter-spacing:.05em}

/* Bolded keywords inside the panel bullets. --ice against the --mist body text
   rather than a heavier weight alone: at 15.5px on a dark ground, weight on its
   own barely separates, and the lift in brightness is what the eye actually
   catches when it is scanning rather than reading. */
.binfo-list b{font-weight:800;color:var(--ice)}
html[lang^="zh"] .binfo-list b{font-weight:700}

/* The top rung's "Best price" line reuses the upsell row's shape so the slot
   does not jump when the shopper steps up to it — same height, same padding,
   same icon column. It is a span, not a button: there is nowhere to go from
   the largest box, and a control that looks pressable but is not is worse than
   no control. Hover and press states are dropped for the same reason. */
.up-best{cursor:default}
.up-best:hover,.up-best:active{background:inherit;transform:none}


/* The compare-at price, before the total it is being compared with. Muted and
   a size down so the figure the shopper is actually paying stays the loud one
   — a struck price at equal weight makes the row read as two prices rather
   than as one price and its anchor. */
.dr-tot .dt-v{display:inline-flex;align-items:baseline;gap:8px}
.dr-tot .dt-was{
  font-size:.72em;font-weight:700;color:var(--mist);opacity:.75;
  text-decoration:line-through;text-decoration-thickness:1.5px;
  font-variant-numeric:tabular-nums;
}
.dr-tot .dt-was[hidden]{display:none}

/* ============================================================
   CART DRAWER - SHORT VIEWPORT

   The panel was tuned against a 390x844 phone, using 844 as the height. No
   phone ever gives a web page 844px. Safari keeps its address bar, so the
   small viewport a 6.1" phone actually reports is around 660, an SE around
   629, a small Android around 615 - and the panel is 100svh, so it gets that
   number, not the spec sheet's. Measured against real numbers the panel
   needed 679px. It ran 19px over on a 6.1", 38px on an SE, 47px on a small
   Android, which is why the line item sat half under the header on a real
   device: the body had scrolled.

   Three things close it.

   The express-wallet row came out of the markup: 101px that rendered as
   empty green on a real phone, under a "More ways to pay" link with nothing
   above it. The table's fruit row came out too, as a verbatim duplicate of
   the line item three rows above it. Together, -134px, on every screen.

   The rest is here, and only here. Above 900px of viewport nothing below
   applies and the panel keeps the spacing it was drawn with; below 900px it
   eases its own chrome, and below 800px it tightens it properly.

   Those numbers started at 720 and 645, tuned when the panel held less. The
   cart has since gained a line of its own — the fruit count under the box
   name — and a row of two controls for a discount code and an order note, and
   both earn their place. Re-measured with them in, the band from 660 to 745
   was the one left short: a Vietnamese cart on a 15 Pro ran 30px over. Raising
   both steps puts every phone back inside one screen, and the only viewport
   that now sees the untouched spacing is one tall enough not to need it.

   Every value below is a padding, a margin, a gap or one icon. No copy is
   dropped, nothing is hidden, and NO font-size is touched: a shopper who has
   turned text size up keeps every point of it, which is the whole reason the
   type went to rem. On a tall screen none of this applies.

       needs 679px  ->  646 after the two deletions   (fits a 6.1" at 660,
                                                       and a Pro Max at 745
                                                       with no trimming at all)
                    ->  621 with the gentle step      (fits an SE at 629)
                    ->  576 with the tight step       (fits a 615 Android)

   Below about 570px of viewport it scrolls again, and it should: a cart that
   hides its own checkout button to avoid a scrollbar is worse than one that
   scrolls. .dr-body keeps overflow-y:auto for exactly that case.
   ============================================================ */
@media (max-height: 900px){
  .drawer .dr-step{padding-top:7px;padding-bottom:7px}
  .drawer .dr-step .ds-title{margin-top:5px}
  .drawer .dr-body{gap:6px}
  .drawer .line{padding-bottom:7px}
  .drawer .dr-eta{padding:7px 11px;margin-top:9px}
  .drawer .dr-eta .de-ico{width:34px;height:34px;padding:8px}
  .drawer .dr-tbl{margin-top:6px}
  .drawer #dr-up{margin-top:7px}
  .drawer .dr-tot{padding-top:5px;padding-bottom:5px;margin-top:3px;margin-bottom:5px}
  .drawer .dr-foot{padding-top:10px}
  .drawer .dr-guar{margin-top:6px}
}
@media (max-height: 800px){
  .drawer .dr-step{padding-top:5px;padding-bottom:5px}
  .drawer .dr-step .ds-title{margin-top:3px}
  .drawer .dr-body{gap:5px}
  .drawer .line{padding-bottom:5px}
  .drawer .line-bot{margin-top:5px}
  .drawer .dr-eta{padding:5px 11px;margin-top:7px}
  .drawer .dr-eta .de-ico{width:31px;height:31px;padding:7px}
  .drawer .dr-tbl{margin-top:4px}
  .drawer #dr-up{margin-top:5px}
  .drawer .dr-tot{padding-top:3px;padding-bottom:3px;margin-top:2px;margin-bottom:3px}
  .drawer .dr-foot{padding-top:8px;padding-bottom:calc(9px + env(safe-area-inset-bottom))}
  .drawer .dr-guar{margin-top:4px}
}

/* ============================================================
   CART DRAWER - DISCOUNT CODE AND ORDER NOTE

   Collapsed, this is one row of two text buttons: about 28px, which is what
   the body has spare on the smallest phone the panel is built to fit. Neither
   field is on screen until it is asked for, so the cart still opens as one
   screen with a button on it rather than a form.

   Open, the panel is allowed to scroll. That is deliberate. A shopper typing a
   code has a keyboard over half the screen and wants the input, not the
   guarantee line under the button, and the input is the top of the pane so it
   stays above the keyboard on both iOS and Android.

   The input is 16px on purpose and must stay 16px: iOS Safari zooms the whole
   page when a focused field is set smaller, and on a fixed panel that zoom
   cannot be undone by scrolling. It is the one place in the drawer where the
   type does not step down with the viewport.
   ============================================================ */
/* Pushed to the bottom of the body rather than left hanging under the taxes
   line. On a tall phone the cart's contents need about 290px of a 460px body,
   and that 170px of slack used to sit as one block of empty green between
   "Taxes and fees" and the total — the thing that read as broken in the
   screenshot from a real device. margin-top:auto spends it as the gap between
   the order and the two things that are not part of it, which is a separation
   the eye can explain. On a short phone there is no slack, auto resolves to 0,
   and the row sits tight under the table exactly as before. */
.dr-extra{margin-top:auto;padding-top:8px}

.dx-tabs{display:flex;gap:18px;align-items:center}
.dx-tab{
  display:inline-flex;align-items:center;gap:6px;
  background:none;border:0;padding:4px 0;margin:0;cursor:pointer;
  font-family:var(--ui);font-size:0.875rem;font-weight:700;
  color:var(--mist);letter-spacing:-.005em;
  text-decoration:underline;text-underline-offset:3px;
  text-decoration-color:rgba(234,244,238,.28);text-decoration-thickness:1px;
}
.dx-tab svg{width:15px;height:15px;flex:0 0 auto;color:var(--gold)}
.dx-tab:hover,.dx-tab:focus-visible{color:var(--ice);text-decoration-color:var(--gold)}
.dx-tab[aria-expanded="true"]{color:var(--ice);text-decoration-color:var(--gold)}
html[lang^="zh"] .dx-tab{font-family:var(--cjk),var(--ui)}

.dx-pane{margin-top:7px}
.dx-pane[hidden]{display:none}
.dx-sr{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;
  clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0}

.dx-row{display:flex;gap:7px;align-items:stretch}
.dr-extra input,.dr-extra textarea{
  flex:1 1 auto;min-width:0;width:100%;
  background:var(--card);border:1px solid var(--rule);border-radius:11px;
  padding:9px 11px;color:var(--ice);
  font-family:var(--ui);font-size:16px;font-weight:600;line-height:1.25;
  -webkit-appearance:none;appearance:none;
}
.dr-extra input{text-transform:uppercase;letter-spacing:.04em}
.dr-extra textarea{resize:none;font-weight:500;letter-spacing:0}
.dr-extra input::placeholder,.dr-extra textarea::placeholder{
  color:var(--mist);opacity:.7;text-transform:none;letter-spacing:0;font-weight:500;
}
.dr-extra input:focus,.dr-extra textarea:focus{
  outline:none;border-color:var(--gold);box-shadow:0 0 0 3px rgba(245,193,54,.16);
}

.dx-go{
  flex:0 0 auto;border:0;border-radius:11px;padding:0 16px;cursor:pointer;
  background:var(--gold);color:var(--ink);
  font-family:var(--ui);font-size:0.9375rem;font-weight:800;letter-spacing:-.005em;
}
.dx-go[disabled]{opacity:.55;cursor:default}
html[lang^="zh"] .dx-go{font-family:var(--cjk),var(--ui)}

.dx-msg{
  margin:6px 0 0;font-family:var(--ui);font-size:0.8125rem;font-weight:600;
  color:var(--mist);line-height:1.3;
}
.dx-msg[hidden]{display:none}
.dx-msg.bad{color:#FF9A8A}
.dx-msg.ok{color:var(--gold)}
html[lang^="zh"] .dx-msg{font-family:var(--cjk),var(--ui)}

/* The applied code. Gold hairline rather than a filled chip: it is a
   confirmation the eye should find, not a second thing competing with the
   button underneath. */
.dx-on{
  display:flex;align-items:center;gap:8px;margin-top:8px;
  padding:7px 8px 7px 11px;border-radius:12px;
  background:rgba(245,193,54,.08);border:1px solid rgba(245,193,54,.42);
}
.dx-on[hidden]{display:none}
.dxo-ico{flex:0 0 auto;display:grid;place-items:center;width:16px;height:16px;color:var(--gold)}
.dxo-ico svg{width:100%;height:100%}
.dx-on b{
  flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  font-family:var(--ui);font-size:0.875rem;font-weight:800;color:var(--ice);letter-spacing:.03em;
}
.dxo-amt{flex:0 0 auto;font-family:var(--ui);font-size:0.875rem;font-weight:800;color:var(--gold)}
.dxo-x{
  flex:0 0 auto;display:grid;place-items:center;width:26px;height:26px;
  background:none;border:0;padding:0;cursor:pointer;color:var(--mist);border-radius:50%;
}
.dxo-x svg{width:13px;height:13px}
.dxo-x:hover,.dxo-x:focus-visible{color:var(--ice);background:rgba(234,244,238,.1)}

/* Collapsed, this row gives up the same chrome as everything else around it. */
@media (max-height: 900px){
  .drawer .dr-extra{padding-top:6px}
  .drawer .dx-tabs{gap:16px}
  .drawer .dx-tab{padding:3px 0}
}
@media (max-height: 800px){
  .drawer .dr-extra{padding-top:4px}
  .drawer .dx-tab{padding:2px 0;font-size:0.84375rem}
}

/* ============================================================
   PURCHASE CARD - THREE LINES, ONE COLUMN

       16 lb Musang King Box              [ MOST POPULAR ]
       4-5 whole durians
       $240 total - $15/lb - save $3.75/lb

   The card was two halves: a left column naming the box and a right column
   stacking the total, the word "Total" under it, and the rate under that. The
   eye had to cross the card and come back, and the three right-hand lines were
   set in a gutter narrow enough that "26.5 lb" could break across two.

   One column reads in the order the choice is actually made: which box, how
   much fruit is in it, what it costs and what that rate saves. The total stays
   the heaviest thing on the line because it is still what is being chosen
   between - these boxes differ by $150, not by three dollars a pound - but it
   no longer needs a column to itself to say so.

   The saving is per pound rather than a dollar total. "Save $120" on a $240
   box invites the reader to work out what the $360 was and whether it was ever
   real; "save $3.75/lb" is checkable against the rate printed two words to its
   left, on the same line, in the same card.
   ============================================================ */
.t-money{
  display:block;margin-top:4px;
  font-family:var(--ui);font-size:0.875rem;font-weight:600;
  color:var(--mist);letter-spacing:-.005em;line-height:1.35;
}
html[lang^="zh"] .t-money{font-family:var(--cjk),var(--ui)}
/* The total is back in its own right-hand column; nothing named .t-tot sits
   inside this line any more. What is left here is the rate and the saving,
   which is the pair that argues for the bigger box. */
/* display and margin, not just the paint: .t-rate is a block-level chip
   everywhere else on the page, and inheriting that here put the rate on its
   own line with 5px above it — the money line rendered as three lines and
   read as a broken card rather than as a sentence. */
.t-money .t-rate{
  display:inline;margin:0;
  font-style:normal;font-weight:800;color:var(--gold);
  background:none;padding:0;border:0;border-radius:0;font-size:1em;letter-spacing:-.005em;
  white-space:nowrap;
}
.t-money .t-savelb{
  display:inline;font-style:normal;font-weight:700;
  color:var(--gold-soft,var(--gold));white-space:nowrap;
}
/* Each money phrase holds together; the line may wrap BETWEEN them, which is
   what a longer language needs and what English never reaches. */

.tier.on .t-money{color:var(--ice)}

/* Three lines on the left against a two-line column on the right: top-aligned,
   because centring a three-line block against a two-line one leaves the box
   name sitting below the price it belongs to. */
.buy .t-r1{align-items:flex-start}
.buy .t-r1 .t-dot{margin-top:3px}
.buy .t-r1 .t-right{margin-top:1px}
.t-mid{flex:1 1 auto;min-width:0}

/* The cart line's fruit count, under the box weight. Set brighter and heavier
   than the grade line below it: "4-5 whole durians" is what the shopper chose,
   and "AAA · D197 · 3.5-5 lb each" is the small print that qualifies it. */
.drawer .line-fruit{
  display:block;margin-top:2px;
  font-family:var(--ui);font-size:0.90625rem;font-weight:700;
  color:var(--ice);letter-spacing:-.005em;line-height:1.25;
}
.drawer .line-fruit[hidden]{display:none}
html[lang^="zh"] .drawer .line-fruit{font-family:var(--cjk),var(--ui)}
@media (max-height: 800px){
  .drawer .line-fruit{font-size:0.875rem;margin-top:1px}
}

/* ---------------------------------------- the cart line, given its width ----
   The text column was 170px of a 290px row and both the box name and the grade
   line wrapped inside it, which is 38px of a panel that was 12px from fitting.
   Neither string is long: "16 lb Musang King Box" needs about 175px and "AAA ·
   D197 · 3.5-5 lb each" about 156px at a step down. The column simply was not
   being given them.

   The thumbnail gives back 12px — it is a 4:5 crop of the same fruit shown
   full-size two screens ago, so it is a reminder rather than a photograph, and
   nothing in it is lost at 54px that could be seen at 66. The grade line drops
   one step of type, which suits it: it is the small print that qualifies the
   fruit count above it, not a line anyone reads first. */
.drawer .line-ph{width:clamp(48px,6.6svh,54px);height:clamp(48px,6.6svh,54px)}
.drawer .line-spec{
  font-size:clamp(0.75rem,1.8svh,0.8125rem);margin-top:3px;
}
.drawer .line-top{gap:11px}

/* A third step, for the shortest viewport a phone actually reports — a small
   Android at 615, which came out 6px over. Six pixels is not worth a design
   decision, so this takes them from the four places nobody will miss them:
   the thumbnail, the arrival row's mark, and the two paddings that sit either
   side of the extras row. Below about 570px it scrolls, and should. */
@media (max-height: 630px){
  .drawer .dr-body{gap:4px}
  .drawer .line-ph{width:44px;height:44px}
  .drawer .dr-eta .de-ico{width:28px;height:28px;padding:6px}
  .drawer .dr-extra{padding-top:5px}
  .drawer .dr-guar{margin-top:3px}
}

/* The product page's band, with the step marker and the decorative fruit gone.
   It was laid out as a grid with a column reserved for a 117px image; with
   nothing to put there the copy would have sat in a narrow gutter beside empty
   space. One column, and the padding comes down to what two lines need. */
.dg-step--plain{
  display:block;
  padding-top:14px;padding-bottom:14px;
  min-height:0;
}
.dg-step--plain .ds-copy{display:block;width:100%;min-width:0}
.dg-step--plain .ds-title{margin-top:0}

/* ------------------------------------- the card title, in the H1's face ----
   The box name was set in the UI face while the product title above it is the
   display face — two typefaces doing the same job a few hundred pixels apart.
   It reads as one family now: same font-family and the same 'wdth' 90 the H1
   carries, with opsz at 40 because these are 17px, not 30.

   Specificity is deliberate. Two rules already claim this element at (0,2,0)
   — .t-r1 .t-qty and .buy .t-qty — and both set var(--ui); a third at the same
   weight would have been decided by source order, which is how the earlier
   .t-qty display-face rule ended up losing silently.

   Caps come from the language file, not text-transform: 磅 has no case, so a
   transform would be a no-op there and a lie about where the styling lives.
   Letter-spacing goes to zero because the tight tracking that suited mixed
   case closes caps up too far. */
.buy .t-r1 .t-qty{
  font-family:var(--dsp);
  font-variation-settings:'wdth' 90,'opsz' 40;
  font-weight:800;
  letter-spacing:0;
}
html[lang^="zh"] .buy .t-r1 .t-qty{
  font-family:var(--cjk),var(--dsp);
  font-variation-settings:normal;font-weight:700;letter-spacing:0;
}

/* ============================================================
   PURCHASE CARD, SECOND PASS

   Four changes, all of them about the row arguing for itself.
   ============================================================ */


/* The heading, no longer a card. A filled, bordered box above four filled,
   bordered boxes read as a fifth option. */
.ladder-h{
  margin:0 0 10px;padding:0;border:0;background:none;
  font-size:clamp(1.1875rem,5vw,1.375rem);font-weight:800;
  letter-spacing:-.02em;line-height:1.15;color:var(--ice);
}


/* --------------------------------------------------- the hierarchy fix ----
   The bold, dominant figure ASCENDED across the ladder — $165, $215, $260,
   $340 — while the figure that argues for the bigger box was small gold text
   underneath. The loudest number on every card was the reason not to buy it.

   The two move toward each other rather than swapping outright. The total
   stays the larger of the pair because a shopper still has to know what they
   are about to pay before they can weigh a rate; it just stops shouting. The
   rate comes up to within a few points of it, in gold, so the descending
   column is the thing the eye follows down the ladder. */
.buy .t-right .t-tot{
  font-size:clamp(1.375rem,5.6vw,1.5625rem);letter-spacing:-.03em;
}
.buy .t-money{
  font-size:1.0625rem;margin-top:5px;
}
.buy .t-money .t-rate{
  font-size:1.0625rem;font-weight:800;color:var(--gold);
}


/* The row is type only again: radio, then weight / fruit count / rate on the
   left, and the price alone on the right. The gap stays at the tighter 9px the
   thumbnail forced — it reads better than the 12px it replaced. */
.buy .t-r1{gap:10px}

/* The ladder's heading: title on the left, the shipping promise on the right,
   and real air under it. The heading sat 10px off the first card, which read
   as a caption stuck to the box rather than a heading over four of them. */
.ladder-head{
  display:flex;align-items:baseline;justify-content:space-between;
  gap:12px;flex-wrap:wrap;margin:0 0 16px;
}
.ladder-h{margin:0}
/* A badge, not a line of text. Gold on a gold-tinted ground with a hairline,
   so it reads as a stamped guarantee rather than as a second heading — and so
   it holds its own against the yellow MOST POPULAR strip further down instead
   of being outshouted by it. */
.ladder-ship{
  flex:0 0 auto;display:inline-flex;align-items:center;gap:6px;
  padding:5px 11px;border-radius:var(--r-pill,999px);
  background:rgba(245,193,54,.12);border:1px solid rgba(245,193,54,.45);
  white-space:nowrap;
}
.ladder-ship svg{width:13px;height:13px;flex:0 0 auto;fill:currentColor;color:var(--gold)}
.ladder-ship b{
  font-family:var(--ui);font-size:0.8125rem;font-weight:800;
  letter-spacing:-.005em;color:var(--gold);
}
html[lang^="zh"] .ladder-ship b{font-family:var(--cjk),var(--ui);letter-spacing:0}
@media (max-width:359px){
  .ladder-ship{padding:4px 9px;gap:5px}
  .ladder-ship b{font-size:0.75rem}
  .ladder-ship svg{width:12px;height:12px}
}

/* A touch larger — it is the line the choice is made on. */
.buy .t-r1 .t-qty{font-size:clamp(1.1875rem,4.9vw,1.3125rem)}

/* -------------------------------- heading and badge, on one line ----------
   Two problems, one of them invisible.

   The size I set on .ladder-h never applied: .buy h2 is (0,1,1) and .ladder-h
   is (0,1,0), so the heading rendered at 24px, not the 19-22 the clamp asks
   for. Scoping to .buy .ladder-h wins it back. This is the fourth time in this
   file a single-class rule has lost silently to a two-part one — when a rule
   looks ignored, check what else claims the element before changing the value.

   Then the pair still needed about 4px at 360px, so the badge gives up a point
   of type and two of padding, and the row's gap comes down. Measured at 360 in
   all four languages, Vietnamese being the widest, everything sits on one line
   with room to spare. flex-wrap stays on as the safety net: a shopper running
   large text should get a stacked heading rather than a clipped one. */
.buy .ladder-h{font-size:clamp(1.0625rem,4.4vw,1.3125rem)}
.ladder-head{gap:10px}
.ladder-ship{padding:5px 9px;gap:5px}
.ladder-ship b{font-size:0.75rem}
.ladder-ship svg{width:12px;height:12px}

/* ------------------------------------------- the delivery promise ---------
   The shape a US shopper already knows how to read: the date in white, bold,
   leading; how long is left to order for it underneath, in gold. Amazon put
   thirty years of training behind this layout and there is nothing to gain by
   inventing a different one for the same fact.

   The countdown is a separate node rather than a clause, so it can vanish
   after the cut-off without leaving a dangling sentence — and so it can be
   repainted every thirty seconds without touching the date beside it. */
/* ---------------------------------- the delivery promise, above the button --
   Sits between the last box card and Add to cart, which is the Amazon
   position: under the price, before the button, where it is the last thing
   read and can still change the choice.

   No card, no fill — a rule above it and air below. It is a statement of fact
   at the moment of decision, and boxing it would make it look like another
   thing to evaluate rather than the answer to the last question. */
.buy-deliv{
  display:flex;align-items:flex-start;gap:9px;
  margin:14px 0 12px;padding:12px 0 0;
  border-top:1px solid var(--rule,rgba(244,249,246,.15));
}
.buy-deliv[hidden]{display:none}
.bd-ic{
  flex:0 0 auto;display:grid;place-items:center;width:19px;height:19px;margin-top:1px;color:var(--gold);
}
.bd-ic svg{width:100%;height:100%;fill:currentColor}
.bd-tx{display:block;min-width:0}
.buy-deliv b{
  display:block;font-family:var(--ui);font-size:0.96875rem;font-weight:800;
  letter-spacing:-.01em;line-height:1.3;color:var(--ice);
}
.buy-deliv i{
  display:block;margin-top:2px;font-style:normal;font-family:var(--ui);
  font-size:0.875rem;font-weight:700;letter-spacing:-.005em;color:var(--gold);
}
.buy-deliv i[hidden]{display:none}
html[lang^="zh"] .buy-deliv b,html[lang^="zh"] .buy-deliv i{
  font-family:var(--cjk),var(--ui);letter-spacing:0;
}

/* The chevron was 12x9 — a wide, short glyph, which is the right shape for an
   arrow and the wrong one for a cross. The X is square and wants stroke, not
   fill. */
.drawer .dr-step .dr-x svg{width:15px;height:15px;stroke:currentColor;fill:none}


/* ------------------------------- the announcement bar, with the cart open --
   Gold on dark is the loudest thing on this page by design — which is right
   until a panel opens in front of it, and then it competes with the panel.
   Faded and desaturated to sit with the rest of the dimmed page rather than
   floating above it. It is not hidden: the free-shipping promise stays legible
   for anyone who looks up at it while deciding. */
html.dg-drawer .topbar{opacity:.32;filter:saturate(.55)}
@media (prefers-reduced-motion:no-preference){
  .topbar{transition:opacity .28s ease,filter .28s ease}
}

/* ------------------------------------ the cart header, without its card ----
   .dg-step paints a gradient and a hairline border and rounds itself to 20px,
   which was right when it was a step band carrying a counter and a photograph.
   With the counter and the fruit gone it is a close button, a language pill
   and the word "Your cart" — and a filled, bordered box around that reads as
   a panel inside a panel, the same thing the product side's heading was doing
   before it went to plain text.

   Kept: the grid, so the bar stays above the title. Dropped: the fill, the
   border, the radius, and the side inset that held the card off the edges —
   the header lines up with the line item under it now instead of floating in
   from 14px. A hairline underneath does the separating that the box was
   doing, at one pixel instead of a whole surface. */
.drawer .dr-step{
  background:none;border:0;border-radius:0;overflow:visible;
  border-bottom:1px solid var(--rule,rgba(244,249,246,.13));
  margin:0 16px;
  padding:clamp(7px,1.2svh,11px) 0 clamp(9px,1.5svh,13px);
}
.drawer .dr-step .ds-copy{padding-left:0}

/* ------------------------------------- the total, without its card --------
   Same move as the cart header above it. The total sat on var(--jade-lift) in
   a 16px-radius box, inset 14px from the panel's edges — a filled surface
   between the line item and the gold button, both of which are already
   surfaces. Three stacked cards to say one number.

   Its own border-top comes off with the fill. .dr-foot already draws a
   hairline directly above it, and with the box gone the two sat about ten
   pixels apart and read as a double rule. One line, from the footer.

   The figures keep every point of their size — nothing about the total gets
   quieter, it just stops being boxed. Zero side padding so "Total" starts on
   the same left edge as the Checkout button under it. */
.drawer .dr-tot{
  background:none;border-radius:0;border-top:0;
  padding-left:0;padding-right:0;
}

/* The summary sits in the footer now, tight above the total, and the payment
   marks take the guarantee line's place under the button. */
.drawer .dr-foot .dr-tbl{margin:0 0 clamp(5px,1svh,9px)}
.drawer .dr-tbl .tb-row{padding:clamp(2px,.5svh,5px) 0}
.drawer .dr-pay{margin-top:clamp(7px,1.3svh,11px)}
.drawer .dr-pay .pay{justify-content:center;gap:6px;margin:0}
.drawer .dr-pay .pay svg,.drawer .dr-pay .pay img,.drawer .dr-pay .pay .pay-icon{
  height:22px;width:auto;
}
@media (max-height: 645px){
  .drawer .dr-pay{margin-top:6px}
  .drawer .dr-pay .pay svg,.drawer .dr-pay .pay img,.drawer .dr-pay .pay .pay-icon{height:19px}
}

/* --------------------------- paying for the summary rows -------------------
   Subtotal, shipping and the payment marks are new height on a panel that had
   none spare: 8px over on a 6.1" phone, 36px on a small Android. Taken back
   from three places, none of which is a fact the shopper needs.

   The arrival row's second line goes. It read "Ships Monday · overnight" under
   "Arrives Tuesday, 9/1" — the shopper wants the day it lands, and the day it
   leaves is the explanation, which the product page now states in full above
   the button. With one line left the mark comes down to match it.

   The summary's rows and the payment marks give up a few points each below
   720, and again below 645. */
.drawer .dr-eta .de-copy i{display:none}
.drawer .dr-eta{padding-top:9px;padding-bottom:9px}
.drawer .dr-eta .de-ico{width:32px;height:32px;padding:7px}

@media (max-height: 780px){
  .drawer .dr-tbl .tb-row{padding:2px 0}
  .drawer .dr-foot .dr-tbl{margin-bottom:3px}
  .drawer .dr-pay{margin-top:7px}
  .drawer .dr-pay .pay svg,.drawer .dr-pay .pay img,.drawer .dr-pay .pay .pay-icon{height:19px}
  .drawer .dr-eta{padding-top:7px;padding-bottom:7px}
  .drawer .dr-eta .de-ico{width:29px;height:29px;padding:6px}
}
@media (max-height: 645px){
  .drawer .dr-tbl .tb-row{padding:1px 0}
  .drawer .dr-pay{margin-top:5px}
  .drawer .dr-pay .pay svg,.drawer .dr-pay .pay img,.drawer .dr-pay .pay .pay-icon{height:17px}
  .drawer .dr-eta{padding-top:5px;padding-bottom:5px}
  .drawer .dr-eta .de-ico{width:26px;height:26px;padding:5px}
}

/* The last 13px, for a small Android in Vietnamese — the tightest combination
   the panel has to hold. Four places, two or three points each: the button's
   floor, the footer's lid, the upsell's lead-in, and the payment marks. */
@media (max-height: 630px){
  .drawer .dr-cta{min-height:46px}
  .drawer .dr-foot{padding-top:6px}
  .drawer #dr-up{margin-top:3px}
  .drawer .dr-pay{margin-top:4px}
  .drawer .dr-pay .pay svg,.drawer .dr-pay .pay img,.drawer .dr-pay .pay .pay-icon{height:15px}
  .drawer .dr-eta{padding-top:4px;padding-bottom:4px}
}

/* The total's right column stacks: the price, then what it saved, under it. */
.drawer .dr-tot{align-items:flex-start}
.drawer .dr-tot .dt-v{display:flex;flex-direction:column;align-items:flex-end;gap:0}
.drawer .dr-tot .dt-now{display:inline-flex;align-items:baseline;gap:8px}
/* Its own type, not the price column's. Moving this line into .dt-v put it
   inside the rule that sets the big figure's face and its -.045em tracking —
   at 14.5px that is -1.44px, which closed the word gaps and rendered
   "You save $144" as "Yousave$144". Inherited tracking is the second time a
   move into a new parent has silently restyled this panel's text. */
.drawer .dr-tot .dt-save{
  display:block;margin-top:1px;text-align:right;
  font-family:var(--ui);font-variation-settings:normal;
  letter-spacing:-.005em;
}
html[lang^="zh"] .drawer .dr-tot .dt-save{font-family:var(--cjk),var(--ui);letter-spacing:0}
.drawer .dr-tot .dt-save[hidden]{display:none}

/* The proof strip's heading in the display face, like every other heading on
   the page. It was set in the UI face — the only section title on the page
   that was — so it read as a caption above the photographs rather than as the
   heading of a section. Same face, same width axis and same weight as the H1
   and "Choose your box"; opsz at 40 because it is 15.5px, not 30. */
.proof-lead{
  font-family:var(--dsp);
  font-variation-settings:'wdth' 90,'opsz' 40;
  font-weight:800;letter-spacing:-.015em;
}
html[lang^="zh"] .proof-lead{
  font-family:var(--cjk),var(--dsp);font-variation-settings:normal;
  font-weight:700;letter-spacing:0;
}

/* The masthead is one white line with the trust figures under it. The gold
   second line and the shared row with the stars are both gone: the title has
   the full width now, so it stays on one line at a size worth reading. */
.fold-head .fh-top{display:block}
.fold-head h1.dsp{font-size:clamp(1.4375rem,6.2vw,2rem)}
.fold-head .fh-proof{gap:10px 14px}
.fold-head .fh-proof .rating{margin:0;flex:0 0 auto}

/* ============================================================
   THE PROOF STRIP — LARGER, AND MOVING

   Bigger first: at 84-100px the faces in a group shot were about eight pixels
   across, which is not a photograph of people, it is a swatch. Half again as
   wide reads as somebody's kitchen table.

   Then it drifts. The track holds the eight photographs twice and slides left
   by exactly 50% before repeating — 50% is the start of the ninth item, an
   identical copy of the first, so there is no seam. The trailing padding is
   what makes that land exactly: with a uniform gap and no padding, half the
   track's width falls in the MIDDLE of a gap and the loop jumps by half a gap
   every cycle.

   Slow on purpose — about 28 pixels a second. This is reassurance for someone
   deciding whether to spend $165, not a slot machine. It stops on hover and
   whenever anything inside has focus, so a photograph can still be opened,
   and it does not run at all under prefers-reduced-motion, where the strip
   stays exactly the scrollable rail it was.
   ============================================================ */
.proof-rail{
  --proof-gap:10px;
  overflow:hidden;margin:0;padding:0;
  /* No bleed past the container. It was pulled out by a guessed gutter width
     — var(--fold-gutter, 20px), a variable this theme does not define — and
     the 20px fallback did not match the real padding, so the rail stuck 4px
     past each edge and the whole page scrolled sideways on a phone. The loop
     needs no bleed to read as endless: the strip is three times the width of
     the rail, so a photograph is always cut by both edges anyway. */
}
/* No gap on the track. Each strip already carries a trailing padding equal to
   one gap, so the two halves butt together at exactly the right spacing — a
   gap here would be counted twice and put the halfway point 5px before the
   start of the second copy, which is a 5px jump once every 42 seconds. */
.proof-track{display:flex;width:max-content;gap:0}
.proof .proof-strip{
  display:flex;gap:var(--proof-gap);margin:0;padding:0 var(--proof-gap) 0 0;
  list-style:none;overflow:visible;width:max-content;
}
.proof .proof-strip > li{flex:0 0 auto}

@media (prefers-reduced-motion:no-preference){
  .proof-track{animation:dg-proof-drift 42s linear infinite}
  .proof-rail:hover .proof-track,
  .proof-rail:focus-within .proof-track{animation-play-state:paused}
}
@keyframes dg-proof-drift{
  from{transform:translate3d(0,0,0)}
  to{transform:translate3d(-50%,0,0)}
}

/* Reduced motion: no drift, and the rail goes back to being swipeable. */
@media (prefers-reduced-motion:reduce){
  .proof-rail{overflow-x:auto;scrollbar-width:none;-webkit-overflow-scrolling:touch}
  .proof-rail::-webkit-scrollbar{display:none}
}

/* Half again as large. */
.proof .proof-shot{width:clamp(126px,34vw,152px)}

/* ------------------------------ the footer's rule, inset to match --------
   The header's rule stops 16px from each edge, because it is a border on an
   element with a 16px side margin. The footer's ran the full width of the
   panel, because it is a border on an element that IS the full width — two
   rules doing the same job at two different lengths, and the long one cut the
   panel in half.

   Drawn as a background gradient rather than a border, so it can be inset
   without moving the footer or its button: a 1px band across the top, clipped
   to transparent for the first and last 16px. The border itself comes off, or
   both would render.

   The footer's side padding comes to 16px at the same time. It was 18px while
   the body and the header were on 16, so the Checkout button sat two pixels
   inboard of every line item above it — invisible on its own and exactly the
   kind of thing that makes a panel feel slightly off without being nameable. */
.drawer .dr-foot{
  border-top:0;
  padding-left:16px;padding-right:16px;
  background-image:linear-gradient(to right,
    transparent 0 16px,
    var(--rule,rgba(244,249,246,.13)) 16px calc(100% - 16px),
    transparent calc(100% - 16px) 100%);
  background-repeat:no-repeat;
  background-size:100% 1px;
  background-position:left top;
}

/* ------------------------------- the badge, back to a corner pill --------
   As a full-width gold band it outweighed everything inside the card. The eye
   went MOST POPULAR, BEST VALUE, and never reached the numbers — and two solid
   bars chopped four tiers into segments so the ladder stopped reading as one
   comparable set.

   A pill on the card's top-left corner carries the same word at a fraction of
   the weight. The card gets top padding rather than the pill being pulled
   outside it: .tier has overflow:hidden, so anything with a negative offset is
   clipped, which is what put the strip inside the card in the first place. */
.buy .tier:has(.t-rec){padding-top:0}
.buy .t-rec{
  position:static;display:inline-block;width:auto;box-sizing:border-box;
  margin:10px 0 0 13px;
  padding:3px 9px;border-radius:var(--r-pill,999px);
  background:rgba(245,193,54,.14);
  border:1px solid rgba(245,193,54,.5);
  color:var(--gold);
  font-family:var(--ui);font-size:0.6875rem;font-weight:800;letter-spacing:.07em;
  line-height:1.35;text-transform:uppercase;
}
html[lang^="zh"] .buy .t-rec{font-family:var(--cjk),var(--ui);letter-spacing:.02em}
/* The selected card is already gold-outlined; a gold-tinted pill inside it
   would sit on almost the same value, so it goes solid there. */
.buy .tier.on .t-rec{background:var(--gold);border-color:var(--gold);color:var(--ink)}
/* No hanging pill any more, so the cards no longer need a gap above them. */
.buy .tier:has(.t-rec),.buy .tier:has(.t-save){margin-top:0}

/* ============================================================
   PURCHASE CARD — FRUIT, AND THE BADGE IN THE PRICE COLUMN
   ============================================================ */

/* The pile. 72px, which is where the halved fruit's flesh still reads as
   flesh; at the 50px this was first tried, it did not. Fixed square so 2, 3,
   4 and 6 share a baseline and the type beside them keeps one left edge. */
.buy .t-pile{flex:0 0 auto;display:block;width:72px;height:72px}
.buy .t-pile img{width:100%;height:100%;object-fit:contain;display:block}
@media (max-width:359px){ .buy .t-pile{width:62px;height:62px} }

/* The badge, top-right, only as wide as its words — and the empty slot that
   keeps the prices on one baseline when a rung has no badge. Both are the
   same height, so the four cards line up whatever badges they carry. */
.buy .t-right{display:flex;flex-direction:column;align-items:flex-end;gap:0}
.buy .t-rec,.buy .t-rec-gap{
  display:block;box-sizing:border-box;
  height:22px;margin:0 0 5px;
}
.buy .t-rec{
  position:static;width:auto;
  padding:3px 9px;border-radius:var(--r-pill,999px);
  background:rgba(245,193,54,.14);
  border:1px solid rgba(245,193,54,.5);
  color:var(--gold);
  font-family:var(--ui);font-size:0.6875rem;font-weight:800;letter-spacing:.06em;
  line-height:1.15;text-transform:uppercase;white-space:nowrap;
}
html[lang^="zh"] .buy .t-rec{font-family:var(--cjk),var(--ui);letter-spacing:.02em}
.buy .tier.on .t-rec{background:var(--gold);border-color:var(--gold);color:var(--ink)}
.buy .t-rec-gap{width:1px;background:none;border:0}
/* Nothing hangs off the card any more, so the rows sit flush together. */
.buy .tier:has(.t-rec),.buy .tier:has(.t-save){margin-top:0}
.buy .tier:has(.t-rec){padding-top:0}

/* -------------------------- the badge stops sizing the price column -------
   .t-right is a flex column aligned right, so its width is the widest child —
   which was the badge. "BEST SELLER" is 40px wider than "POPULAR", so the two
   longer-badged cards took 40px out of their own text column and wrapped the
   fruit line, and the ladder rendered at two card heights (98px and 118px)
   for four rungs meant to be read as one set.

   The badge comes out of the flow and pins to the card's top-right corner, so
   the column is sized by the price alone and every card measures the same
   whatever its badge says. The empty slot goes with it — the padding does that
   job now, on every card equally. */
.buy .tier{position:relative}
/* left:auto matters. Four older bare ".t-rec" rules still set left:14/16/18px
   from the generation when this pill hung off the card's corner. With those
   inherited AND right:12px set here, the box has both edges pinned, so it
   stretched the full width of the card and printed itself across the title.
   Only the right edge anchors it. */
.buy .t-rec{
  position:absolute;top:10px;left:auto;right:12px;bottom:auto;
  width:auto;margin:0;z-index:1;
}
.buy .t-rec-gap{display:none}
.buy .t-right{padding-top:27px}

/* The cultivar, picked out inside the title. "h1 em" further up this file is
   display:block — that is the old two-line masthead — so it has to be put back
   inline here or the name drops onto its own line again. */
.fold-head h1.dsp em{display:inline;font-style:normal;color:var(--gold)}

/* ------------------------------ the badge stays put when a card is chosen --
   ".buy .tier.on .t-rec" further up sets top:auto — left over from a version
   where the selected card's badge was positioned differently. It is (0,3,0)
   against the (0,2,0) that places the pill, so it won on the selected card
   only, and top:auto on an absolutely positioned box drops it to its static
   position: the middle of the card, beside the fruit count.

   Pinned here at (0,3,0) for both states, so selecting a card cannot move it.
   Every offset is stated rather than just top, because the same older block
   also carries left and bottom values. */
.buy .tier .t-rec,
.buy .tier.on .t-rec{
  position:absolute;top:10px;right:12px;left:auto;bottom:auto;
  width:auto;margin:0;z-index:1;
}
