/* m-demo — mobile/responsive layer for the "Live demo" interactive store.
   Inline styles in index.html win on specificity, so overrides here generally
   need !important. Loaded after checkout-modal.css.

   OWNS: .m-demo section rhythm, .m-demo-toggle, the fake browser window
   (.m-demo-window / .m-demo-body), the demo storefront, the cart drawer and
   the in-store checkout page (.m-co-grid / .m-co-main / .m-co-summary).
   Does NOT touch: the MOSS checkout component itself (.co-* / checkout-modal.css),
   or any other section's hooks.

   ── STRATEGY (round 2) ─────────────────────────────────────────────────────
   The demo is a ~980x640 desktop store inside a browser frame. It is re-flowed
   for phones, never scaled down.

   Round 1 kept the desktop metaphor of a *fixed-height* window whose views
   scroll internally. On a phone that produced two nested scrollers inside a
   window covering ~91% of the screen: escaping the checkout's inner scroller
   cost ~900–1120px of fling, and the store list clipped a third of the
   catalogue with no visible affordance. Round 2 drops the fixed box below
   900px:

     1. the JS scale-in transform on .mz-demo-frame is switched off <=900px
        (it desynced the frame from the page gutters and shrank type), and
        will-change is cleared so fixed-position overlays resolve against the
        viewport rather than the frame;
     2. .m-demo-body becomes HEIGHT: AUTO. The window is as tall as whatever
        view it is showing and the *page* does the scrolling — one scroller,
        no trap, no clipped products, no viewport-unit height that resizes
        under the finger while the URL bar collapses, and no dead white space
        under a single row of products on a tablet;
     3. because the window is now taller than the screen, the two overlays
        that must stay reachable are anchored to the viewport instead of the
        window: the cart becomes a bottom sheet (a right-hand sheet in
        landscape) and the contained MOSS pop-up is centred on screen. Their
        primary CTAs can therefore never land below the fold;
     4. product cards go horizontal (image left / detail right) so all three
        products read like a mobile store list;
     5. the checkout grid stacks form-then-summary, and the 6-col field grid
        re-flows City / State+ZIP. Landscape is wide enough for the real
        two-column grid, so the stack is width- AND height-aware;
     6. the browser chrome drops its traffic lights <=640px and the URL pill
        goes full width — a phone browser's address bar, not a desktop window.

   Desktop (>=1100px) is untouched: fixed 640px body, internal scrolling,
   contained drawer/pop-up, JS scale-in all still live. 901–1099px keeps that
   desktop layout too, with one correction: the coach bubble hangs below its
   card there, so it is flipped to point up (it used to aim down into blank
   page).

   ── ROUND 3 (see the block near the bottom of this file) ───────────────────
   The section now has to read as ONE screen on a phone, because it is a
   scroll-snap target. It is compressed to fit and the store is rebuilt as a
   proper mobile list. Round 3 also owns assets/m-demo.js, which re-frames the
   window when a view change resizes it — height:auto means "Continue
   shopping" would otherwise strand you outside the demo.

   ── SHARED SCALE (mirrors m-sections.css) ──────────────────────────────────
   width      side pad   section v-pad   h2      lede
   >=1100     32         88              50      18
   <=1080     28         76              clamp   18
   <=900      24         64              34      17
   <=640      20         56              30      16
   <=400      16         48              27      15.5
   <=360      16         44              26      15.5
   ─────────────────────────────────────────────────────────────────────────── */


/* Cart sheet entrance. Vertical on the bottom sheet, horizontal on the
   landscape side sheet. Reduced motion is honoured at the bottom of the file. */
@keyframes m-sheet-up   { from { transform: translateY(100%); } to { transform: none; } }
@keyframes m-sheet-side { from { transform: translateX(100%); } to { transform: none; } }


/* ══════════════════════════════════════════════════════════════════════════
   ALL WIDTHS — two spacing corrections from the whole-site audit.
   ══════════════════════════════════════════════════════════════════════════ */

/* The eyebrow's 12px square carried an inline margin-left:1px, so the first
   ink of this section's first line sat 1px inside the gutter that every h2
   below it starts on (and on a different line from the four other sections,
   which had 3 / 1.5 / 0.5). Zero everywhere. */
.m-demo .mz-rev > div:first-child > span:first-child { margin-left: 0 !important; }

/* The demo caption is a <p>: its default 1em bottom margin (13px) collapses
   out through the wrapper and lands on the section's bottom padding, so the
   gap into "WHY MOSS" measured 13px more than the contract at every width
   from 700 up. The <p> is the last thing in the wrapper; it owns no bottom
   rhythm of its own. */
.m-demo > div > p:last-child { margin-bottom: 0 !important; }


/* ══════════════════════════════════════════════════════════════════════════
   THE END-OF-FLOW TOAST  (markup lives outside <section id="demo">, but it is
   produced only by this section's flow, so the mobile behaviour is ours).
   Scoped to .m-toast alone — no positioning, colour or type is touched.

   The box is fixed with left:50% and no `right`, so shrink-to-fit resolved
   its available width against (viewport − 50%) — half the screen. At 390 it
   wrapped to five lines in 195px and its own max-width:92vw (359px) was
   unreachable; at 320 it grew to six lines and covered the Mega Duck row and
   half that row's Add button. width:max-content is measured against the
   content rather than the containing block, so the line breaks where the
   sentence does — and the max-width cap still stops it touching the edges.
   translateX(-50%) is left alone, which keeps the mz-toast-in rise intact.
   ══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 900px) {
  .m-toast {
    width: max-content !important;
    max-width: calc(100vw - 32px) !important;
  }
}
@media (max-width: 400px) {
  .m-toast { max-width: calc(100vw - 24px) !important; }
}


/* ══════════════════════════════════════════════════════════════════════════
   <= 1080px — tighten desktop only. Frame + layout unchanged.
   ══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 1080px) {
  .m-demo { padding-top: 76px !important; padding-bottom: 76px !important; }
}


/* ══════════════════════════════════════════════════════════════════════════
   <= 900px — the demo stops being a desktop screenshot.
   Scale off, window height auto, page owns the scroll, checkout stacks.
   ══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 900px) {
  .m-demo { padding-top: 64px !important; padding-bottom: 64px !important; }

  .m-demo h2 { font-size: 34px !important; line-height: 1.08 !important; letter-spacing: -0.02em !important; }
  /* margin-top is the page's h2→lede gap at this step of the scale (18, not 16) */
  .m-demo .mz-rev p { font-size: 17px !important; line-height: 1.58 !important; margin-top: 18px !important; }

  /* ── mode toggle ───────────────────────────────────────────────────────── */
  .m-demo-toggle { margin-top: 26px !important; gap: 9px !important; }
  .m-demo-toggle button {
    min-height: 44px !important;
    padding: 0 18px !important;
    font-size: 14px !important;
  }
  /* ── the mode hint goes ────────────────────────────────────────────────
     Two reasons, either of which would be enough. It is two lines of 13px
     prose explaining what the two buttons directly above it already name,
     and it is 46px of the vertical budget the section needs to read as one
     screen. It is also no longer TRUE below 901px: the pop-up copy promises
     a pop-up "contained to your checkout window", and on these widths the
     pop-up is anchored to the viewport (it has to be — the window is taller
     than the screen). Tapping the toggle demonstrates the difference better
     than a caption can. Restored in full at >=901px. */
  .m-demo-toggle > div:last-child { display: none !important; }

  /* ── frame ─────────────────────────────────────────────────────────────
     transform:none kills the JS scale-in (inline transform is beaten by
     !important). will-change MUST be cleared too: `will-change: transform`
     creates a containing block, which would make the viewport-anchored
     cart sheet and MOSS pop-up resolve against the frame instead of the
     screen — the exact bug they exist to avoid. */
  .mz-demo-frame {
    transform: none !important;
    will-change: auto !important;
    margin-top: 18px !important;
  }

  /* overflow:clip clips exactly like overflow:hidden but does NOT create a
     scroll container — which is what lets the address bar below be sticky
     against the viewport rather than against a box that never scrolls. */
  .m-demo-window {
    max-width: 100% !important;
    border-radius: 14px !important;
    box-shadow: 0 18px 44px rgba(8, 24, 16, 0.14) !important;
    overflow: clip !important;
  }

  /* ── the address bar stays with you ────────────────────────────────────
     height:auto makes the checkout view a ~1450px-tall "window", so the only
     piece of browser chrome scrolled away after ~50px and the rest of the
     journey had nothing saying "this is still the merchant's own site".
     Sticking it under the site nav keeps that signal for the whole scroll. */
  .m-demo-window > div:first-child {
    position: sticky !important;
    top: 64px !important;
    z-index: 4 !important;
  }

  /* ── the window body: as tall as its content, page-scrolled ───────────
     No fixed height, no dvh/svh clamp, no inner scroller. One scroller on
     the whole page. */
  .m-demo-body {
    height: auto !important;
    min-height: 0 !important;
    overflow: visible !important;
    display: block !important;
  }
  .m-demo .m-store-head,
  .m-demo .m-store-head + div {
    flex: none !important;
    overflow: visible !important;
  }
  /* the checkout view stops being an absolutely-positioned inner scroller */
  .m-demo-body > div:has(> .m-co-grid) {
    position: static !important;
    overflow: visible !important;
  }
  /* "Scroll down to pay with MOSS" only described the inner scroller that no
     longer exists — and it landed on the City / Full name field. */
  .m-demo-body > .mz-coach { display: none !important; }

  /* ── overlays are anchored to the viewport, not to the tall window ──────
     The contained MOSS pop-up lives in an x-dc host with display:contents;
     giving the host a box is how it gets pinned without writing a .co-* rule. */
  .m-demo-body > .sc-host-x {
    display: block !important;
    position: fixed !important;
    inset: 0 !important;
    z-index: 120 !important;
  }
  /* …and freeze the document while it is up. overscroll-behavior only stops
     chaining out of the card's own scroller; a drag starting on the backdrop
     was never in a scroller at all, so it scrolled the marketing page and
     left the pop-up floating over a different section.
     scrollbar-gutter keeps a classic scrollbar's 15px reserved for the
     duration of the lock. Headless Chrome uses overlay scrollbars so it never
     showed up there, but at 641–900 in a desktop browser the whole page
     jumped 15px sideways the moment the pop-up opened. */
  html:has(.m-demo-body > .sc-host-x) {
    overflow: hidden !important;
    scrollbar-gutter: stable !important;
  }

  /* ── store header ──────────────────────────────────────────────────────── */
  .m-demo .m-store-head { padding: 16px 18px !important; }
  .m-demo .m-store-head > button { min-height: 44px !important; padding: 0 18px !important; }

  /* ── product grid: narrower track so a tablet still shows all three ────── */
  .m-demo .m-store-head + div { padding: 20px 20px 26px !important; }
  .m-demo .m-store-head + div > div:last-child {
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)) !important;
    gap: 14px !important;
  }
  .m-demo .m-store-head + div > div:last-child > div > div:first-child { height: 128px !important; }
  .m-demo .m-store-head + div > div:last-child button { min-height: 44px !important; padding: 0 18px !important; }
  /* caption floor: the SKU chip (10.5px) and the safety line (11px) are the
     two smallest strings in the demo */
  .m-demo .m-store-head + div > div:last-child > div > div:first-child > span,
  .m-demo .m-store-head + div > div:last-child > div > div:nth-child(2) > div:nth-child(3) {
    font-size: 12px !important;
  }

  /* ── "Add one to your cart" coach ──────────────────────────────────────
     The old placement sat straight across the product copy and hid the "Bath
     use only" safety line at nearly every width. The bubble now points UP
     into the Add button (flex order reversed, triangle flipped) and is given
     clear space to sit in: below the card where the cards are side by side,
     inside a strip of the card in the one-column phone layout. */
  .m-demo .m-store-head + div .mz-coach {
    right: 8px !important;
    flex-direction: column-reverse !important;
  }
  .m-demo .m-store-head + div .mz-coach > div:last-child {
    border-top: 0 !important;
    border-bottom: 8px solid #15291D !important;
    margin-right: 42px !important;
  }

  /* the cart count badge sits on the 12px caption floor at EVERY mobile width,
     not just <=640 (it computed to 11px at 641–900 before this) */
  .m-demo .m-store-head span[style*="min-width: 20px"] { font-size: 12px !important; }

  /* ── cart drawer ───────────────────────────────────────────────────────── */
  .m-demo-body > aside > div:first-child > button {
    min-width: 44px !important;
    min-height: 44px !important;
    align-items: center !important;
    justify-content: center !important;
    padding: 0 !important;
  }
  /* qty stepper + remove: real tap targets */
  .m-demo-body > aside button[style*="width: 28px"] { width: 44px !important; height: 44px !important; font-size: 18px !important; }
  .m-demo-body > aside button[style*="text-decoration: underline"] {
    min-height: 44px !important;
    display: inline-flex !important;
    align-items: center !important;
    font-size: 12.5px !important;
  }

  /* ── in-store checkout: stack the two columns ──────────────────────────── */
  .m-co-grid { grid-template-columns: 1fr !important; }
  .m-co-main {
    border-right: none !important;
    border-bottom: 1px solid #EFEBE4 !important;
    min-height: 0 !important;
    padding: 22px 22px 24px !important;
  }
  /* Summary sits BELOW the form: the point of the demo is reaching the MOSS
     card, so nothing is allowed to push it further down the scroll. The total
     is already shown on the cart's Checkout button and inside the MOSS card. */
  .m-co-summary { padding: 22px 22px 28px !important; }

  /* caption floor: the badge and the summary footer both computed to 11.5px */
  .m-co-main > div:first-child > span[style*="border-radius: 999px"] { font-size: 12px !important; }
  .m-co-summary > div:last-child { font-size: 12px !important; }
  .m-co-summary span[style*="min-width: 18px"] {
    font-size: 12px !important;
    min-width: 20px !important;
    height: 20px !important;
  }
  /* "Secured by MOSS" appeared twice within ~50px whenever the inline MOSS
     card is on the page. The card's own footer is the authoritative one. */
  .m-co-grid:has(.m-co-main > div[style*="rgb(94, 156, 125)"]) .m-co-summary > div:last-child {
    display: none !important;
  }

  /* checkout topbar */
  .m-demo-body div[style*="padding: 15px 22px 15px 14px"] { padding: 8px 14px 8px 8px !important; }

  .m-demo-body div[style*="padding: 15px 22px 15px 14px"] > button {
    min-height: 44px !important;
    padding: 0 10px !important;
  }
}


/* ══════════════════════════════════════════════════════════════════════════
   641–900px — tablet: the checkout is stacked but the window is still wide,
   so the checkout column is centred rather than stretched edge to edge.
   Round 1 did this with percentage padding, which resolves against the grid
   area (not the 620px target) and landed on a 668px measure. A max-width on
   the grid itself is exact at every width.
   ══════════════════════════════════════════════════════════════════════════ */
@media (min-width: 641px) and (max-width: 900px) {
  .m-co-grid { max-width: 664px !important; margin: 0 auto !important; }
}


/* ══════════════════════════════════════════════════════════════════════════
   Cards side by side (>=641px, incl. landscape): the coach bubble hangs just
   BELOW its card. Putting it inside would stretch the whole grid row and
   leave card 1's Add button 46px out of line with the other two.
   ══════════════════════════════════════════════════════════════════════════ */
@media (min-width: 641px) and (max-width: 1099px) {
  /* The bubble hangs BELOW the card here, so it has to point UP — the flip
     (column-reverse + a bottom-edge triangle) used to live only in the <=900
     block, which left 901–1099 with a downward arrow aiming at empty page. */
  .m-demo .m-store-head + div .mz-coach {
    right: 8px !important;
    flex-direction: column-reverse !important;
  }
  .m-demo .m-store-head + div .mz-coach > div:last-child {
    border-top: 0 !important;
    border-bottom: 8px solid #15291D !important;
    margin-right: 42px !important;
  }
  .m-demo .m-store-head + div:has(.mz-coach) { padding-bottom: 58px !important; }
  .m-demo .m-store-head + div > div:last-child > div:has(.mz-coach) { overflow: visible !important; }
  /* the card's own overflow:hidden was what rounded the image tile */
  .m-demo .m-store-head + div > div:last-child > div:has(.mz-coach) > div:first-child {
    border-radius: 15px 15px 0 0 !important;
  }
  .m-demo .m-store-head + div .mz-coach { bottom: -46px !important; }

  /* The cart count badge computed to 11px here. The coach flip above was
     carried up to 1099 in round 2 but the 12px caption floor was not — same
     boundary, half applied. */
  .m-demo .m-store-head span[style*="min-width: 20px"] { font-size: 12px !important; }
}


/* ══════════════════════════════════════════════════════════════════════════
   <= 640px — phone. Browser chrome becomes an address bar, product cards
   go horizontal, the cart becomes a bottom sheet, field grid re-flows.
   ══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 640px) {
  .m-demo { padding-top: 56px !important; padding-bottom: 56px !important; }

  .m-demo h2 { font-size: 30px !important; }
  .m-demo .mz-rev p { font-size: 16px !important; margin-top: 14px !important; }
  .m-demo > div > p:last-child { font-size: 12.5px !important; margin-top: 14px !important; }

  .m-demo-toggle { margin-top: 24px !important; }
  .m-demo-toggle button { padding: 0 15px !important; font-size: 13.5px !important; }

  .m-demo-window {
    border-radius: 12px !important;
    box-shadow: 0 12px 30px rgba(8, 24, 16, 0.13) !important;
  }

  /* ── browser chrome → phone address bar ────────────────────────────────
     Traffic lights are a desktop-window metaphor and read as clutter at this
     width; a single full-width URL pill is what a phone browser looks like,
     and it keeps the "this is the merchant's own site" signal intact. */
  .m-demo-window > div:first-child { padding: 8px 10px !important; gap: 0 !important; }
  .m-demo-window > div:first-child > div:first-child,
  .m-demo-window > div:first-child > div:last-child { display: none !important; }
  .m-demo-window > div:first-child > div:nth-child(2) { flex: 1 1 auto !important; }
  .m-demo-window > div:first-child > div:nth-child(2) > div {
    width: 100% !important;
    justify-content: center !important;
    padding: 6px 12px !important;
    font-size: 12px !important;
  }

  /* ── store header ──────────────────────────────────────────────────────── */
  .m-demo .m-store-head { padding: 13px 14px !important; gap: 10px !important; }
  .m-demo .m-store-head > img { height: 26px !important; width: 26px !important; }
  .m-demo .m-store-head > div > div:first-child { font-size: 15.5px !important; }
  .m-demo .m-store-head > button { padding: 0 15px !important; font-size: 13.5px !important; }

  /* ── product list: one column, horizontal cards ────────────────────────── */
  .m-demo .m-store-head + div { padding: 16px 14px 20px !important; }
  .m-demo .m-store-head + div > div:first-child { margin-bottom: 12px !important; font-size: 12px !important; }
  .m-demo .m-store-head + div > div:last-child {
    grid-template-columns: 1fr !important;
    gap: 12px !important;
  }
  .m-demo .m-store-head + div > div:last-child > div { flex-direction: row !important; }
  /* image tile → fixed-width thumbnail */
  .m-demo .m-store-head + div > div:last-child > div > div:first-child {
    width: 108px !important;
    height: auto !important;
    flex: 0 0 108px !important;
    align-self: stretch !important;
  }
  .m-demo .m-store-head + div > div:last-child > div > div:first-child > svg {
    width: 58px !important;
    height: 51px !important;
  }
  .m-demo .m-store-head + div > div:last-child > div > div:first-child > span {
    top: 8px !important;
    left: 8px !important;
    font-size: 12px !important;              /* never below the 12px caption floor */
  }
  /* detail column */
  .m-demo .m-store-head + div > div:last-child > div > div:nth-child(2) {
    padding: 13px 14px 13px 15px !important;
  }
  .m-demo .m-store-head + div > div:last-child > div > div:nth-child(2) > div:nth-child(3) {
    font-size: 12px !important;              /* "Bath use only" */
  }
  .m-demo .m-store-head + div > div:last-child > div > div:nth-child(2) > div:last-child {
    padding-top: 11px !important;
  }
  .m-demo .m-store-head + div > div:last-child button {
    min-height: 44px !important;
    padding: 0 22px !important;
    font-size: 13.5px !important;
  }

  /* coach bubble: one column, so below the card would land on the next
     product — it gets a strip of its own inside the coached card instead */
  .m-demo .m-store-head + div > div:last-child > div:has(.mz-coach) > div:nth-child(2) {
    padding-bottom: 50px !important;
  }
  .m-demo .m-store-head + div .mz-coach { bottom: 7px !important; }
  .m-demo .m-store-head + div .mz-coach > div:first-child { font-size: 12px !important; padding: 7px 11px !important; }

  /* ── cart: a viewport-anchored bottom sheet ────────────────────────────
     The window is now taller than the screen, so a drawer pinned inside it
     put "Checkout · $54.99" hundreds of pixels below the fold the moment you
     tapped Add. Pinning the sheet (and its scrim) to the viewport guarantees
     the primary CTA and the "Now check out" coach are always on screen, and
     is what a phone store actually does. */
  .m-demo-body > div:has(+ aside) {
    position: fixed !important;
    inset: 0 !important;
    z-index: 119 !important;
  }
  .m-demo-body > aside {
    position: fixed !important;
    top: auto !important;
    right: 0 !important;
    bottom: 0 !important;
    left: 0 !important;
    width: 100% !important;
    height: auto !important;
    max-height: min(84vh, 560px) !important;
    max-height: min(84svh, 560px) !important;
    border-left: none !important;
    border-radius: 18px 18px 0 0 !important;
    box-shadow: 0 -18px 50px rgba(8, 24, 16, 0.22) !important;
    z-index: 120 !important;
    animation: m-sheet-up .32s cubic-bezier(.22, 1, .36, 1) both !important;
    overscroll-behavior: contain !important;
  }
  /* a modal that scrolls the marketing page behind it is the one nested-scroll
     bug worth keeping a guard against */
  .m-demo-body > aside > div[style*="overflow-y: auto"] { overscroll-behavior: contain !important; }
  /* grabber */
  .m-demo-body > aside::before {
    content: "";
    flex: none;
    width: 38px;
    height: 4px;
    border-radius: 999px;
    background: #DFD9CF;
    margin: 9px auto 1px;
  }
  .m-demo-body > aside > div:first-child { padding: 10px 14px 12px !important; }
  .m-demo-body > aside > div[style*="overflow-y: auto"] { padding-left: 14px !important; padding-right: 14px !important; }
  .m-demo-body > aside > div:last-child { padding: 16px 14px calc(16px + env(safe-area-inset-bottom)) !important; }

  /* count badges — keep them on the 12px caption floor */
  .m-demo .m-store-head span[style*="min-width: 20px"] { font-size: 12px !important; }
  .m-co-summary span[style*="min-width: 18px"] {
    font-size: 12px !important;
    min-width: 20px !important;
    height: 20px !important;
  }

  /* ── in-store checkout ─────────────────────────────────────────────────── */
  .m-co-main { padding: 18px 14px 20px !important; }
  .m-co-main > div:first-child { margin-bottom: 12px !important; flex-wrap: wrap !important; }
  .m-co-summary { padding: 18px 14px 24px !important; }

  /* topbar: drop the "Secure checkout" tail — it duplicates the padlock in the
     address bar and is the first thing to collide at this width */
  .m-demo-body div[style*="padding: 15px 22px 15px 14px"] > span:last-child { display: none !important; }
  .m-demo-body div[style*="padding: 15px 22px 15px 14px"] { gap: 9px !important; }

  /* field grid: Email/Name/Address/Country + City full width, State+ZIP halves.
     Rhythm is tightened too — every px saved here is a px closer to the MOSS
     card, which is what the demo exists to show. */
  .m-co-main > div[style*="repeat(6, 1fr)"] { gap: 10px !important; }
  .m-co-main > div[style*="repeat(6, 1fr)"] > label:nth-child(4) { grid-column: span 6 !important; }
  .m-co-main > div[style*="repeat(6, 1fr)"] > label:nth-child(5),
  .m-co-main > div[style*="repeat(6, 1fr)"] > label:nth-child(6) { grid-column: span 3 !important; }
  /* 16px keeps iOS from zooming the page when a field takes focus */
  .m-co-main > div[style*="repeat(6, 1fr)"] input {
    font-size: 16px !important;
    height: 44px !important;
  }
  .m-co-main > div[style*="repeat(6, 1fr)"] span { font-size: 12.5px !important; margin-bottom: 3px !important; }

  /* embedded MOSS card wrapper (the card itself belongs to checkout-modal.css) */
  .m-co-main > div[style*="rgb(94, 156, 125)"] { margin-top: 20px !important; }
  .m-co-main > div[style*="rgb(94, 156, 125)"] > div:first-child { padding: 12px 13px !important; gap: 9px !important; }

  /* pop-up mode: payment-method chips */
  .m-co-main > div[style*="flex-wrap: wrap"] { gap: 7px !important; }
  .m-co-main > div[style*="flex-wrap: wrap"] > span { font-size: 12px !important; padding: 8px 10px !important; }
}


/* ══════════════════════════════════════════════════════════════════════════
   <= 400px — small phone
   ══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 400px) {
  .m-demo { padding-top: 48px !important; padding-bottom: 48px !important; }
  .m-demo h2 { font-size: 27px !important; }
  .m-demo .mz-rev p { font-size: 15.5px !important; }

  .m-demo-toggle button { padding: 0 13px !important; font-size: 13px !important; }

  .m-demo .m-store-head { padding: 12px !important; }
  .m-demo .m-store-head > div > div:first-child { font-size: 15px !important; }
  .m-demo .m-store-head > button { padding: 0 13px !important; }

  .m-demo .m-store-head + div { padding: 14px 12px 18px !important; }
  .m-demo .m-store-head + div > div:last-child > div > div:first-child {
    width: 92px !important;
    flex: 0 0 92px !important;
  }
  .m-demo .m-store-head + div > div:last-child > div > div:nth-child(2) { padding: 12px 12px 12px 13px !important; }
  .m-demo .m-store-head + div > div:last-child button { padding: 0 15px !important; }
  .m-demo .m-store-head + div .mz-coach > div:last-child { margin-right: 36px !important; }

  .m-demo-body > aside > div:first-child,
  .m-demo-body > aside > div:last-child { padding-left: 12px !important; padding-right: 12px !important; }
  .m-demo-body > aside > div[style*="overflow-y: auto"] { padding-left: 12px !important; padding-right: 12px !important; }

  .m-co-main { padding: 16px 12px 18px !important; }
  .m-co-summary { padding: 16px 12px 22px !important; }
}


/* ══════════════════════════════════════════════════════════════════════════
   <= 360px — last-resort tightening
   ══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 360px) {
  .m-demo { padding-top: 44px !important; padding-bottom: 44px !important; }
  .m-demo h2 { font-size: 26px !important; }

  .m-demo-toggle button { padding: 0 11px !important; font-size: 12.5px !important; }

  .m-demo .m-store-head + div > div:last-child > div > div:first-child {
    width: 82px !important;
    flex: 0 0 82px !important;
  }
  .m-demo .m-store-head + div > div:last-child > div > div:first-child > svg { width: 48px !important; height: 42px !important; }
  .m-demo .m-store-head + div > div:last-child > div > div:nth-child(2) > div:nth-child(2) { font-size: 12px !important; }
  .m-demo .m-store-head + div > div:last-child button { padding: 0 13px !important; }
  .m-demo .m-store-head + div .mz-coach > div:last-child { margin-right: 32px !important; }
}


/* ══════════════════════════════════════════════════════════════════════════
   ROUND 3/4 — the phone store (PORTRAIT only).

   Round 2 made .m-demo-body height:auto, which means the window is exactly
   its content: compressing the section == compressing the store. Round 3 used
   that to fit eyebrow-through-store inside one 390x844 screen, and paid for
   it partly out of the store and partly out of the heading block.

   ROUND 4 GIVES THE HEADING BLOCK BACK. Taking the section's vertical padding
   to 34/30 and the eyebrow/h2/lede/toggle gaps to 11/10/12 put this section
   off the page's shared scale by −26 to -38px at every phone width, and it
   showed: scrolling out of .m-how into .m-demo, the heading visibly collapsed
   and the section read as a boxed-in ad slot in an otherwise generous page.
   Rhythm beats the one-screen goal — a store you scroll 40px into is a store;
   a heading that breaks the page's rhythm is a defect on every scroll past.

   So the section pad and the heading gaps are back on the contract
   (44/48/56 v-pad; eyebrow→h2 14, h2→lede 14, lede→toggle 28) and the height
   is taken out of the store instead. What the store still gives up, and why
   that and not type or tap targets:
     - the mode-hint line: the two button labels already name the two modes,
       and tapping demonstrates the difference better than 13px of prose.
       Kept at >=641 where it costs nothing.
     - the caption: "no real payment is processed" is already stated in the
       lede two lines above it ("All simulated, no charges."). Nothing is lost
       from the screen, only a duplicate.
     - the "Rubber duckies" grid label: a category heading over a single
       category of three items, directly under the shop's own name.
     - the window's own paddings.
     - the product card is a real mobile list row: the price and Add button
       sit in a right-hand column beside the text instead of under it, so a
       card is as tall as its content rather than the sum of two stacks.
     - round 4: the image tile drops 92→68px (see "the duck" below), which is
       24px of measure handed to the product name and spec line.
   Nothing is removed and nothing shrinks below its floor — the Add button
   keeps its 44px target, the SKU and safety captions stay at 12px, body copy
   and the price stay >=15px.

   Everything here is portrait-gated (min-height: 481px) so the landscape
   block below keeps full ownership of short screens.
   ══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 640px) and (min-height: 481px) {
  /* ── section rhythm: the page's, not the demo's ────────────────────────
     Section padding is inherited from the <=640/<=400/<=360 blocks above
     (56 / 48 / 44) — i.e. the shared scale, unmodified. Only the three
     internal gaps need restating, because the <=900 block tuned them. */
  .m-demo .mz-rev > div:first-child { margin-bottom: 14px !important; }
  .m-demo .mz-rev p { margin-top: 14px !important; line-height: 1.45 !important; }

  .m-demo-toggle { margin-top: 28px !important; gap: 0 !important; }

  .mz-demo-frame { margin-top: 10px !important; }
  /* caption: duplicated by the lede's "All simulated, no charges." */
  .m-demo > div > p:last-child { display: none !important; }

  /* ── browser chrome ────────────────────────────────────────────────────── */
  .m-demo-window > div:first-child { padding: 6px 10px !important; }
  .m-demo-window > div:first-child > div:nth-child(2) > div { padding: 4px 12px !important; }

  /* ── store header: the 44px Cart button is the floor, padding is not ───── */
  .m-demo .m-store-head { padding: 8px 12px !important; }

  /* ── product list ──────────────────────────────────────────────────────── */
  .m-demo .m-store-head + div {
    padding: 9px 11px 11px !important;
    position: relative !important;   /* the coach's containing block, see below */
  }
  .m-demo .m-store-head + div > div:first-child { display: none !important; }
  .m-demo .m-store-head + div > div:last-child { gap: 10px !important; }

  /* ── the duck, and the tile it lives in ────────────────────────────────
     The owner asked for the artwork 30% smaller (58x51 -> 41x36) and it
     stays there. Round 3 only took the tile from 108 to 92, which left a
     41x36 duck in a 92x96 panel — 16% of the tile inked, and with a pill of
     SKU type in the corner the code, not the product, was the largest thing
     in the product image.

     Round 4 brings the TILE down to the art instead of the art up to the
     tile: one 68px width at every phone width (was 92 / 80 / 72). The duck
     now spans 60% of the tile's width and the thumbnail reads as a deliberate
     thumbnail. The 24px given up at 414/430 goes to the name and spec line.

     68 is not arbitrary: it is the widest the tile can be while the duck
     still dominates it, and the narrowest it can be while the SKU below
     stays on one line at 12px (the longest code sets 57.8px of type). */
  .m-demo .m-store-head + div > div:last-child > div > div:first-child {
    width: 68px !important;
    flex: 0 0 68px !important;
    padding-bottom: 19px !important;   /* centres the duck above the SKU band */
  }
  .m-demo .m-store-head + div > div:last-child > div > div:first-child > svg {
    width: 41px !important;
    height: 36px !important;
  }

  /* ── the SKU comes out of the artwork ──────────────────────────────────
     As a corner pill at 12px the chip was 71.8px wide inside a 72px tile, so
     "QUACK-01" broke over two lines and the second line rendered on top of
     the duck's head at 320 and 360 (390 cleared it by 0.2px — one font
     metric from the same break). Instead of buying the pill more room, the
     SKU stops competing with the art at all: it becomes a caption band
     across the foot of the thumbnail, one line, on the 12px caption floor,
     with the artwork centred in the panel above it. */
  .m-demo .m-store-head + div > div:last-child > div > div:first-child > span {
    top: auto !important;
    left: 0 !important;
    right: 0 !important;
    bottom: 0 !important;
    padding: 3px 4px !important;
    border-radius: 0 !important;
    background: rgba(255, 255, 255, 0.86) !important;
    text-align: center !important;
    white-space: nowrap !important;
    overflow: hidden !important;
    font-size: 12px !important;
  }

  /* card → list row: [thumb] [name/spec/safety] [price over Add].
     The detail column becomes a 2-col grid; the price+Add row (the card's
     last child) spans all three text rows in column 2 instead of stacking
     underneath them. */
  .m-demo .m-store-head + div > div:last-child > div > div:nth-child(2) {
    display: grid !important;
    grid-template-columns: minmax(0, 1fr) auto !important;
    align-items: center !important;
    column-gap: 10px !important;
    padding: 9px 11px !important;   /* symmetric — 11/12 was the page's only odd pair */
  }
  /* All three rows are the same height on purpose: the spec line always
     occupies exactly two lines, so a one-line spec and a three-line spec
     can't make neighbouring products different sizes.
     text-wrap:balance is what makes those two lines readable. Left to greedy
     wrapping all three products dropped a single word onto line 2 —
     "buoyant", "silent", "in bass" — three orphans stacked down the list.
     Balancing splits the measure evenly instead, and it cannot change the
     block's height because the height is fixed at 2.64em regardless. */
  .m-demo .m-store-head + div > div:last-child > div > div:nth-child(2) > div:nth-child(2) {
    line-height: 1.32 !important;
    height: 2.64em !important;
    display: -webkit-box !important;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    overflow: hidden !important;
    text-wrap: balance;
  }
  .m-demo .m-store-head + div > div:last-child > div > div:nth-child(2) > div:nth-child(1),
  .m-demo .m-store-head + div > div:last-child > div > div:nth-child(2) > div:nth-child(2),
  .m-demo .m-store-head + div > div:last-child > div > div:nth-child(2) > div:nth-child(3) {
    grid-column: 1 !important;
  }
  /* price and Add share one axis: the column is as wide as the wider of the
     two and both stretch to fill it, so the price is centred directly over
     its own button on every row. */
  .m-demo .m-store-head + div > div:last-child > div > div:nth-child(2) > div:last-child {
    grid-column: 2 !important;
    grid-row: 1 / span 3 !important;
    flex-direction: column !important;
    align-items: stretch !important;
    justify-content: center !important;
    gap: 5px !important;
    margin-top: 0 !important;
    padding-top: 0 !important;
  }
  .m-demo .m-store-head + div > div:last-child > div > div:nth-child(2) > div:last-child > span {
    text-align: center !important;
  }

  /* ── "Add one to your cart" coach ──────────────────────────────────────
     It used to be given a strip of its own card (round 2) and then a gap
     below its card (first cut of round 3). Both made product 1 taller than
     products 2 and 3 — a broken-looking rhythm in a list where every row
     should match. So the bubble is out of the card's flow entirely: the card
     goes position:static, the product wrapper is the containing block, and
     the coach lives in a strip of the wrapper's own padding.

     Round 4 moves that strip from the BOTTOM of the list to the TOP. Sitting
     under the list it pointed up into the third product's Add button while
     reading "Add one to your cart" — it was aimed at the last thing on the
     screen. Above the list it points DOWN at the first product's Add button,
     which is the one it means and the first one you see. (Pointing down is
     the markup's own default, so the round-2 flip is undone here rather than
     re-specified.) Cards keep one even 10px rhythm and nothing is overlaid —
     the "Bath use only" line is untouched at every width. */
  .m-demo .m-store-head + div > div:last-child > div { position: static !important; }
  /* undo round 2's in-card strip — the coached card is now a normal row */
  .m-demo .m-store-head + div > div:last-child > div:has(.mz-coach) > div:nth-child(2) {
    padding-bottom: 9px !important;
  }
  .m-demo .m-store-head + div:has(.mz-coach) {
    padding-top: 44px !important;
    padding-bottom: 11px !important;
  }
  .m-demo .m-store-head + div .mz-coach {
    position: absolute !important;
    top: 4px !important;
    bottom: auto !important;
    left: auto !important;
    right: 11px !important;
    flex-direction: column !important;   /* bubble, then the arrow beneath it */
  }
  .m-demo .m-store-head + div .mz-coach > div:last-child {
    border-top: 8px solid #15291D !important;
    border-bottom: 0 !important;
    margin-right: 33px !important;       /* lands on the Add button's centre */
  }

  /* ── scroll lock behind the viewport-fixed overlays ────────────────────
     overscroll-behavior only stops chaining OUT of the sheet's own scroller;
     a drag that starts on the scrim was never in a scroller at all, so it
     scrolled the marketing page and left the sheet floating over a different
     section. Freezing the document while either overlay is mounted is the
     only thing that covers both. */
  html:has(.m-demo-body > aside),
  html:has(.m-demo-body > .sc-host-x) {
    overflow: hidden !important;
    scrollbar-gutter: stable !important;
  }
  .m-demo-body > div:has(+ aside) { touch-action: none !important; }
}

/* Narrow phones: the right-hand price/Add column is what the name and the
   spec line have to share their measure with, so it is the thing that gives
   width back — not the type in the left column, which stays on its floors.
   The tile no longer varies with width: at 68px it costs less than the two
   narrower tiles it replaces did at 320, so there is nothing left to take. */
@media (max-width: 400px) and (min-height: 481px) {
  .m-demo .m-store-head + div > div:last-child > div > div:nth-child(2) { column-gap: 8px !important; }
  .m-demo .m-store-head + div > div:last-child > div > div:nth-child(2) > div:last-child > span {
    font-size: 15px !important;
  }
}
@media (max-width: 360px) and (min-height: 481px) {
  /* The price used to drop to 14px here. It is the most decision-relevant
     number in a product row and 15px is the body floor; the 12px the tile
     just gave back pays for it. */
  .m-demo .m-store-head + div > div:last-child > div > div:nth-child(2) > div:nth-child(1) {
    font-size: 15px !important;
  }
  .m-demo .m-store-head + div > div:last-child button { padding: 0 12px !important; }
}


/* ══════════════════════════════════════════════════════════════════════════
   Landscape phones (<=480px tall). Height is the scarce axis here, width is
   not: 844x390 has room for the real two-column checkout, and the cart wants
   to be a full-height side sheet rather than a bottom one.
   ══════════════════════════════════════════════════════════════════════════ */
@media (max-height: 480px) and (orientation: landscape) and (max-width: 1099px) {
  .m-demo { padding-top: 44px !important; padding-bottom: 44px !important; }
  .mz-demo-frame { transform: none !important; will-change: auto !important; margin-top: 14px !important; }
  .m-demo h2 { font-size: 30px !important; }
  .m-demo-toggle { margin-top: 20px !important; }

  /* Same page-scroll model as <=900px. It has to be restated here because a
     landscape phone can be wider than 900px (iPhone 16 Pro Max is 956) and
     would otherwise get an absolutely-positioned checkout inside a
     height:auto window — i.e. a collapsed view. */
  .m-demo-body { height: auto !important; min-height: 0 !important; overflow: visible !important; display: block !important; }

  /* ── the address bar stops being sticky here ───────────────────────────
     The <=900px block parks the browser chrome under the site nav so the
     "this is still the merchant's own site" signal survives a long scroll.
     On a 390px-tall screen that signal costs 51px — 13% of the viewport, and
     it is directly over the payload: the integrated success screen renders
     its check medallion at the top of the window, and the sticky bar clipped
     all but the bottom sliver of it at the one moment the demo exists to
     deliver. Height is the scarce axis in landscape; the bar is not worth
     paying for out of it. */
  .m-demo-window > div:first-child { position: static !important; }
  .m-demo .m-store-head { flex: none !important; padding: 9px 14px !important; }
  .m-demo .m-store-head + div { flex: none !important; overflow: visible !important; padding: 10px 14px 14px !important; }
  .m-demo-body > div:has(> .m-co-grid) { position: static !important; overflow: visible !important; }
  .m-demo-body > .mz-coach { display: none !important; }
  .m-demo-body > .sc-host-x { display: block !important; position: fixed !important; inset: 0 !important; z-index: 120 !important; }
  /* the MOSS sheet is taller than a 390px-tall screen, so centring it hides
     its header AND its footer at once. Top-aligning keeps the merchant row
     and the close control on screen; the overlay scrolls for the rest.
     (Placement only — the card's own sizing belongs to m-checkout-fit.css.) */
  .m-demo-body > .sc-host-x > div {
    align-items: flex-start !important;
    padding-top: 6px !important;
    overscroll-behavior: contain !important;
  }
  .m-co-main { min-height: 0 !important; }
  .m-co-grid:has(.m-co-main > div[style*="rgb(94, 156, 125)"]) .m-co-summary > div:last-child { display: none !important; }
  .m-co-main > div:first-child > span[style*="border-radius: 999px"] { font-size: 12px !important; }
  .m-co-summary > div:last-child { font-size: 12px !important; }
  .m-co-summary span[style*="min-width: 18px"] {
    font-size: 12px !important;
    min-width: 20px !important;
    height: 20px !important;
  }

  /* caption floor + coach placement (restated for the >900px landscape case) */
  .m-demo .m-store-head + div > div:last-child > div > div:first-child > span,
  .m-demo .m-store-head + div > div:last-child > div > div:nth-child(2) > div:nth-child(3) {
    font-size: 12px !important;
  }
  .m-demo .m-store-head + div .mz-coach { right: 8px !important; flex-direction: column-reverse !important; }
  .m-demo .m-store-head + div .mz-coach > div:last-child {
    border-top: 0 !important;
    border-bottom: 8px solid #15291D !important;
    margin-right: 42px !important;
  }
  /* A 390px-tall screen cannot hold the whole store: with the site nav taking
     64 and the window's own chrome and header taking ~100, the row of three
     cards starts around the fold and its price/Add line sits below it. What
     these three rules buy is that the first scroll reaches the buttons in one
     short flick rather than two — the card is trimmed to the shortest it can
     be while the Add button keeps its 44px target. */
  .m-demo .m-store-head + div > div:first-child { margin-bottom: 8px !important; }
  .m-demo .m-store-head + div > div:last-child > div > div:nth-child(2) { padding: 11px 14px 12px !important; }
  .m-demo .m-store-head + div > div:last-child button { min-height: 44px !important; }

  /* ── cart: full-height side sheet pinned to the viewport ───────────────
     Round 1's contained drawer computed a 16px-tall item region inside a
     280px window whose header + footer already needed 284px: the line item,
     the −/+ stepper and Remove all rendered outside the clip band. Anchoring
     to the screen removes the constraint entirely; the chrome is compressed
     as well so short screens still show a line item. */
  .m-demo-body > div:has(+ aside) {
    position: fixed !important;
    inset: 0 !important;
    z-index: 119 !important;
  }
  .m-demo-body > aside {
    position: fixed !important;
    top: 0 !important;
    bottom: 0 !important;
    right: 0 !important;
    left: auto !important;
    width: min(420px, 58%) !important;
    height: auto !important;
    max-height: none !important;
    border-left: 1px solid #E6E1D9 !important;
    border-radius: 0 !important;
    box-shadow: -20px 0 60px rgba(8, 24, 16, 0.18) !important;
    z-index: 120 !important;
    animation: m-sheet-side .32s cubic-bezier(.22, 1, .36, 1) both !important;
    overscroll-behavior: contain !important;
  }
  .m-demo-body > aside > div[style*="overflow-y: auto"] { overscroll-behavior: contain !important; }
  /* same scrim-drag leak as portrait — freeze the document under the overlay,
     with the scrollbar's gutter held so a classic scrollbar can't shift the
     page sideways as the lock goes on and off */
  html:has(.m-demo-body > aside),
  html:has(.m-demo-body > .sc-host-x) {
    overflow: hidden !important;
    scrollbar-gutter: stable !important;
  }
  .m-demo-body > div:has(+ aside) { touch-action: none !important; }
  .m-demo-body > aside::before { display: none !important; }
  .m-demo-body > aside > div:first-child { padding: 8px 16px !important; }
  .m-demo-body > aside > div[style*="overflow-y: auto"] { padding: 0 16px !important; }
  .m-demo-body > aside > div[style*="overflow-y: auto"] > div > div { padding: 11px 0 !important; }
  .m-demo-body > aside > div:last-child:has(button) { padding: 10px 16px !important; }
  .m-demo-body > aside > div:last-child:has(button) > div:first-child { margin-bottom: 8px !important; }
  .m-demo-body > aside > div:last-child:has(button) > button { height: 46px !important; font-size: 15px !important; }
  /* the "Card, Apple Pay, Google Pay or USDm" reassurance line duplicates the
     chips on the checkout page and is the first thing to give up its 30px */
  .m-demo-body > aside > div:last-child:has(button) > div:last-child { display: none !important; }
}

/* landscape, but still wide enough for the grid layout */
@media (max-height: 480px) and (orientation: landscape) and (min-width: 641px) and (max-width: 1099px) {
  .m-demo .m-store-head + div > div:last-child > div > div:first-child { height: 68px !important; }
  .m-demo .m-store-head + div > div:last-child > div > div:first-child > svg { width: 48px !important; height: 42px !important; }
  /* width is not the constraint at 844 — restore the real two-column checkout
     so the form and the summary are not five screens apart */
  .m-co-grid { grid-template-columns: 1.4fr 1fr !important; max-width: none !important; margin: 0 !important; }
  .m-co-main { border-right: 1px solid #EFEBE4 !important; border-bottom: none !important; padding: 18px 20px 20px !important; }
  /* the form column is ~1000px tall and the summary ~250, so a stretched
     summary would be one screen of content over three screens of empty
     beige. Sticking it keeps the total beside the form the whole way down. */
  .m-co-summary {
    padding: 18px 20px 22px !important;
    align-self: start !important;
    position: sticky !important;
    top: 76px !important;
    border-radius: 0 0 0 12px !important;
  }
  /* overflow:hidden on the frame makes it a scroll container, which silently
     kills the sticky above. overflow:clip clips identically without one. */
  .m-demo-window { overflow: clip !important; }
}


/* ══════════════════════════════════════════════════════════════════════════
   Reduced motion — the sheet entrances are the only motion added here.
   ══════════════════════════════════════════════════════════════════════════ */
@media (prefers-reduced-motion: reduce) {
  .m-demo-body > aside { animation: none !important; }
}
