/* --- Page --------------------------------------------------------------- */

/* Vertical rhythm from the shared token, so every layout 1 page clears the
   header by the same amount instead of each sheet picking its own literal. */
.app-shell .product-details.spad {
    padding: var(--app-page-top) 0 var(--app-page-bottom);
}

.app-shell .product-details > .container {
    width: 100%;
    max-width: 100%;
    padding-inline: var(--app-pad);
}

/* Stacked on a phone: the gallery reads first, the controls follow. */
.app-shell .product-details > .container > .row > [class*="col-"] {
    flex: 0 0 100%;
    max-width: 100%;
    padding-inline: 0;
}

/* Side by side once there is room for both. */
@media (min-width: 900px) {
    .app-shell .product-details > .container > .row > .col-lg-6 {
        flex: 0 0 50%;
        max-width: 50%;
    }

    .app-shell .product-details > .container > .row > .col-lg-6:first-child {
        padding-right: 20px;
    }
}

/* --- Gallery ------------------------------------------------------------ */

/* The gallery contains a floated thumbnail strip in the desktop sheet; the
   float is cleared below, and this contains anything else that floats inside
   so the description card after it can never slide up into the gallery. */
.app-shell .product__details__pic {
    margin-bottom: 16px;
}

/* Contains the floated thumbnail strip the desktop sheet creates, so whatever
   follows the gallery starts below it rather than sliding up alongside. A
   clearfix rather than overflow, which would clip the gallery arrows. */
.app-shell .product__details__pic::after {
    content: "";
    display: block;
    clear: both;
}

/* margin-right: 0 clears the 15px product_detail2.css gives this frame for its
   desktop float layout, which left the image narrower than the thumbnail strip
   and the description card beneath it. */
.app-shell .product__details__pic__item {
    position: relative;
    margin-right: 0;
    border: 1px solid #eceef1;
    border-radius: 16px;
    background: #fff;
    overflow: hidden;
    /* Square frame so a portrait and a landscape upload occupy the same space
       and the controls below do not jump between products. */
    aspect-ratio: 1 / 1;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 12px;
}

/* "1 / 4" position counter over the artwork, as in the reference. Rendered by
   the template only when there is more than one image. */
/* Bottom-centre rather than a corner: the prev/next arrows sit mid-height on
   both edges, and the top-right corner is where the discount marker goes. */
.app-shell .pd-gallery-count {
    position: absolute;
    bottom: 12px;
    left: 50%;
    transform: translateX(-50%);
    z-index: 2;
    padding: 4px 10px;
    border-radius: 999px;
    background: rgba(255, 255, 255, .92);
    box-shadow: 0 1px 3px rgba(16, 24, 40, .08);
    color: var(--app-muted);
    font-size: 11.5px;
    font-weight: 600;
    line-height: 1.3;
    pointer-events: none;
}

/* Discount marker: the same red .app-tag--off pill the product cards wear
   (app-mobile.css). product_detail.css styles every <p> in this frame as a
   96px strip with a lopsided corner radius, so those box rules are undone
   here and the card badge's own geometry wins. */
.app-shell .product__details__pic__item .app-tag--off {
    position: absolute;
    top: 14px;
    right: 14px;
    left: auto;
    z-index: 3;
    width: auto;
    max-width: none;
    margin: 0;
    padding: 6px 11px;
    border-radius: 8px;
    text-align: left;
    color: #fff;
}

.app-shell .pd-gallery-count .pd-gallery-current {
    color: var(--app-ink);
    font-weight: 700;
}

/* Prev / next over the artwork, as in the reference — round, white, centred on
   each edge. Rendered by the template only when there is more than one image. */
.app-shell .pd-gallery-nav {
    position: absolute;
    top: 50%;
    z-index: 2;
    transform: translateY(-50%);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    padding: 0;
    border: 1px solid #eceef1;
    border-radius: 50%;
    background: rgba(255, 255, 255, .95);
    box-shadow: 0 2px 8px rgba(16, 24, 40, .1);
    color: var(--app-ink);
    font-size: 12px;
    cursor: pointer;
    transition: background .15s ease, border-color .15s ease, color .15s ease;
}

.app-shell .pd-gallery-prev { left: 10px; }
.app-shell .pd-gallery-next { right: 10px; }

.app-shell .pd-gallery-nav:hover {
    border-color: var(--app-theme);
    background: #fff;
    color: var(--app-theme);
}

.app-shell .product__details__pic__item--large,
.app-shell .product__details__pic__item img {
    width: 100%;
    height: 100%;
    /* contain, not cover: a product photo cropped to a square loses the top or
       bottom of the bottle. */
    object-fit: contain;
}

.app-shell .product__details__pic__slider {
    display: flex;
    gap: 8px;
    margin-top: 10px;
    overflow-x: auto;
    scrollbar-width: none;
}

.app-shell .product__details__pic__slider::-webkit-scrollbar {
    display: none;
}

.app-shell .product__details__pic__slider img {
    flex: 0 0 64px;
    width: 64px;
    height: 64px;
    padding: 4px;
    border: 1px solid #eceef1;
    border-radius: 10px;
    background: #fff;
    object-fit: contain;
    cursor: pointer;
}

/* Four or more images render the strip as an owl carousel instead. The shared
   sheets fix each thumb at `width: 90px !important` on grey, which is wider
   than the slot owl gives it on a phone (4 per row), so thumbs overlapped and
   the last one was cut off. Here a thumb fills its slot, up to 72px, and the
   arrows sit in the strip's side padding. The flex/overflow from the plain
   strip above is undone too, since owl lays out its own stage. */
.app-shell .product__details__pic__slider.owl-carousel {
    display: block;
    overflow: visible;
    margin-top: 12px;
    padding: 0 36px;
}

.app-shell .product__details__pic__slider.owl-carousel .owl-stage-outer {
    margin-right: 0;
    padding-right: 0;
}

.app-shell .product__details__pic__slider.owl-carousel .c_item {
    width: 100% !important;
    max-width: 72px;
    height: auto !important;
    aspect-ratio: 1 / 1;
    margin: 0 auto;
    padding: 4px;
    border: 1px solid #eceef1;
    border-radius: 10px;
    background: #fff;
    transition: border-color .15s ease;
}

/* Inset, because .owl-stage-outer clips anything drawn outside the thumb. */
.app-shell .product__details__pic__slider.owl-carousel .c_item.is-active {
    border-color: var(--app-theme);
    box-shadow: inset 0 0 0 1px var(--app-theme);
}

.app-shell .product__details__pic__slider.owl-carousel .owl-nav button.owl-prev,
.app-shell .product__details__pic__slider.owl-carousel .owl-nav button.owl-next {
    width: 28px;
    height: 28px;
    font-size: 13px;
    border-color: #eceef1 !important;
    box-shadow: 0 2px 6px rgba(0, 0, 0, .08);
}

.app-shell .product__details__pic__slider.owl-carousel .owl-nav button.owl-prev:hover,
.app-shell .product__details__pic__slider.owl-carousel .owl-nav button.owl-next:hover {
    border-color: var(--app-theme) !important;
    background: #fff !important;
    color: var(--app-theme) !important;
}

/* The main image already shows "1 / 5", so the dots only repeated it. */
.app-shell .product__details__pic__slider.owl-carousel .owl-dots {
    display: none;
}

/* The thumbnail row shares the main frame's card treatment, and the current
   thumb carries the theme border — the reference marks which image is shown. */
/* float: none is load-bearing. product_detail2.css floats this strip left for
   the desktop layout (`.pd2-classic .product__details__thumb__slider`), and a
   float is out of normal flow — so the description card below it slid up
   underneath the thumbnails instead of starting after them. */
.app-shell .product__details__thumb__slider {
    display: flex;
    float: none;
    width: 100%;
    gap: 10px;
    margin-top: 12px;
    overflow-x: auto;
    scrollbar-width: none;
}

.app-shell .product__details__thumb__slider::-webkit-scrollbar {
    display: none;
}

/* Overrides the 110px green-bordered grey thumb the page's inline <style>
   carries for the older layouts — that block is in the body, so this sheet
   needs the extra .app-shell class to outrank it rather than !important. */
.app-shell .product__details__thumb__slider img.c_item {
    flex: 0 0 64px;
    width: 64px;
    height: 64px;
    float: none;
    margin: 0;
    padding: 4px;
    border: 1px solid #eceef1;
    border-radius: 10px;
    background: #fff;
    object-fit: contain;
    cursor: pointer;
    transition: border-color .15s ease;
}

.app-shell .product__details__thumb__slider img.c_item:hover {
    border-color: var(--app-theme-border, var(--app-theme));
}

.app-shell .product__details__pic__slider img.is-active,
.app-shell .product__details__thumb__slider img.c_item.is-active {
    border-color: var(--app-theme);
    box-shadow: 0 0 0 2px var(--app-theme-soft);
}

/* --- Detail card -------------------------------------------------------- */

.app-shell .product__details__text {
    padding: 16px 14px 16px;
    border: 1px solid #ececf0;
    border-radius: 16px;
    background: #fff;
    box-shadow: 0 2px 10px rgba(0, 0, 0, .04);
}

.app-shell .product__details__text h3,
.app-shell .product__details__text h4 {
    font-size: 17px;
    font-weight: 700;
    line-height: 1.3;
    margin: 0 0 8px;
}

/* --- Heading block ------------------------------------------------------
   Title, the pack-size caption under it, then the price — the stacked order
   the reference uses, rather than title and price crowded onto one row. */

.app-shell .product__details__text .pd-head {
    padding-bottom: 12px;
    margin-bottom: 14px;
    border-bottom: 1px solid #f1f2f4;
}

.app-shell .product__details__text .pd-title {
    margin: 0;
    font-size: 20px;
    font-weight: 800;
    letter-spacing: -.3px;
    line-height: 1.25;
}

/* The brand line above the title, where the vendor shows brands. Small and
   themed, so it reads as a kicker rather than a second heading. */
.app-shell .product__details__text .pd-head .brandName {
    display: block;
    margin-bottom: 5px;
    font-size: 11.5px;
    font-weight: 700;
    letter-spacing: .05em;
    line-height: 1.2;
    text-transform: uppercase;
    color: var(--app-theme);
}

.app-shell .product__details__text .pd-price-row {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 10px;
    margin-top: 12px;
}

/* The price already carries the rule and spacing that separated it from the
   description; inside the heading block the block's own border does that. */
.app-shell .product__details__text .pd-price-row .product__details__price {
    margin: 0;
    padding: 0;
    border-bottom: 0;
    font-size: 23px;
}

.app-shell .product__details__text .pd-unit {
    font-size: 13.5px;
    font-weight: 500;
    color: var(--app-muted);
}

/* --- Labelled field groups ----------------------------------------------
   "SELECT DELIVERY FREQUENCY" / "QUANTITY OF ..." — a small-caps label over
   its control, as in the reference. */

.app-shell .product__details__text .pd-field {
    margin-bottom: 14px;
}

.app-shell .product__details__text .pd-field-label {
    display: block;
    margin-bottom: 8px;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .06em;
    line-height: 1.2;
    text-transform: uppercase;
    color: var(--app-muted);
}

/* The stepper's own bottom margin would double the group's. */
.app-shell .product__details__text .pd-field .product__details__quantity {
    margin-bottom: 0 !important;
}


/* --- Delivery-frequency selector ---------------------------------------- */

.app-shell .pd-freq {
    display: flex;
    gap: 8px;
}

/* The tabs above carry no logic of their own — picking "Subscribe" clicks the
   page's existing .subscribe button (see the .pd-freq-opt handler in
   Slugs/v1/product_detail2.php). With BOTH on screen the customer was offered
   the same choice twice: a One-Time/Subscribe pair at the top and an
   Add To Cart/Subscribe pair below the stepper.
   The tab bar is the control, so the duplicate .subscribe button is hidden —
   but only when the tabs are actually rendered. They appear solely for
   is_subscribable == 2 (both routes offered); a subscribe-only product shows no
   tabs, and there its .subscribe button is the ONLY way to subscribe and must
   stay. :has() scopes the rule to exactly the case that has a duplicate.
   Hidden rather than removed from the template: the JS toggles this button's
   inline display and reads its state, so deleting it would break the flow the
   tabs drive. */
/* NOT display:none. The handler finds its target with
   `$('.subscribe').filter(':visible').first()` — and jQuery's :visible is false
   for a display:none element, so hiding it that way left the tab with nothing
   to click and Subscribe stopped working entirely.
   Collapsed to zero size and taken out of the flow instead: the button is still
   ":visible" to jQuery, so the handler still finds and clicks it, but it
   occupies no space and cannot be seen or tabbed to. */
/* Slugs/v1/product_detail.php has no .detail-btn-wrap: its trigger is a bare
   a.primary-btn.subscribe (in a .col-md-6 for configurable products), so the
   wrapper selector alone missed it and the duplicate Subscribe button showed
   under the tabs there. Same treatment, matched on the button itself. */
.app-shell .product__details__text:has(.pd-freq) .detail-btn-wrap.subscribe,
.app-shell .product__details__text:has(.pd-freq) a.primary-btn.subscribe,
.app-shell .product__details__text:has(.pd-freq) .product-detail-action-buttons > [class*="col-"]:has(> a.primary-btn.subscribe) {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: 0;
    padding: 0;
    border: 0;
    overflow: hidden;
    clip-path: inset(50%);
    pointer-events: none;
    opacity: 0;
}

/* With the pair reduced to one control, Add To Cart takes the full width the
   two used to share rather than sitting at half width with a gap beside it. */
.app-shell .product__details__text:has(.pd-freq) .detail-btn-wrap:not(.subscribe).w-50 {
    width: 100% !important;
}

.app-shell .product__details__text:has(.pd-freq) .product-detail-action-buttons > [class*="col-"]:not(:has(> a.primary-btn.subscribe)) {
    flex: 0 0 100%;
    max-width: 100%;
}

/* Subscribe tab active: quantity is set per day in the subscription panel and
   the order is placed from there, so the one-time quantity label and
   Add To Cart have nothing to do. Keyed off the tab state itself, so every
   path back to One-Time Order restores them. */
.app-shell .product__details__text:has(.pd-freq-opt[data-pd-freq="subscribe"].is-active) .pd-field-qty,
.app-shell .product__details__text:has(.pd-freq-opt[data-pd-freq="subscribe"].is-active) .add_to_cart {
    display: none !important;
}

/* …and the reverse. "Add Credit Card" / "Verify your linked payment method",
   the card note and Confirm Subscription belong to the SUBSCRIBE flow: the
   page reveals them once a schedule is picked there (checkSagePayAdded() shows
   #sage_link when no card is on file). They sit outside the .Sub_show panel the
   One-Time tab hides, so after a trip to Subscribe and back they stayed on
   screen beside Add To Cart — a payment prompt for a cart that needs none.
   Keyed off the tab state, so returning to Subscribe brings them back exactly
   as the script left them. Ids are matched directly because the auto-debit
   gateways (TMC96 / TMC34 / TMC83) render their links outside .submit-container. */
.app-shell .product-details:has(.pd-freq-opt[data-pd-freq="once"].is-active) .submit-container,
.app-shell .product-details:has(.pd-freq-opt[data-pd-freq="once"].is-active) #sage_link,
.app-shell .product-details:has(.pd-freq-opt[data-pd-freq="once"].is-active) #verify_sage_pay,
.app-shell .product-details:has(.pd-freq-opt[data-pd-freq="once"].is-active) .sage_note {
    display: none !important;
}

.app-shell .pd-freq-opt {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    flex: 1 1 0;
    min-width: 0;
    min-height: 44px;
    padding: 9px 12px;
    border: 1px solid #e4e6ea;
    border-radius: 10px;
    background: #fff;
    color: var(--app-ink);
    font-family: inherit;
    font-size: 13px;
    font-weight: 600;
    line-height: 1.2;
    text-align: center;
    cursor: pointer;
    transition: border-color .15s ease, background .15s ease, color .15s ease;
}

.app-shell .pd-freq-opt i {
    font-size: 12px;
    color: var(--app-muted);
}

.app-shell .pd-freq-opt:hover {
    border-color: var(--app-theme-border, var(--app-theme));
    color: var(--app-theme);
}

.app-shell .pd-freq-opt:hover i {
    color: var(--app-theme);
}

.app-shell .pd-freq-opt.is-active {
    border-color: var(--app-theme);
    background: var(--app-theme-soft);
    color: var(--app-theme);
}

.app-shell .pd-freq-opt.is-active i {
    color: var(--app-theme);
}

/* The label can be longer than its half of the row once translated. */
.app-shell .pd-freq-opt > span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Price and the unit label ("20 lts") sit on one baseline with real space
   between them — as inline siblings in the markup they ran together. */
.app-shell .product__details__price {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 8px;
    font-size: 20px;
    font-weight: 800;
    color: var(--app-ink);
    margin: 0 0 16px;
    padding-bottom: 14px;
    border-bottom: 1px solid #f1f2f4;
}

/* The unit / pack-size caption beside the figure. */
.app-shell .product__details__price small,
.app-shell .product__details__price span:not([class]) {
    font-size: 13px;
    font-weight: 500;
    color: var(--app-muted);
}

.app-shell .product__details__price del,
.app-shell .product__details__price s {
    font-size: 14px;
    font-weight: 500;
    color: var(--app-muted);
    margin-left: 6px;
}

.app-shell .product__details__text p,
.app-shell .content-details {
    font-size: 14px;
    line-height: 1.55;
    color: var(--app-muted);
}

/* --- Description panel ---------------------------------------------------
   Titled block, as in the reference. The heading takes the theme dot beside it
   the reference shows; the body keeps the muted body copy above. */

.app-shell .pd-desc {
    margin-top: 18px;
    padding-top: 16px;
    border-top: 1px solid #f1f2f4;
}

/* product_detail2 renders the description in its own block after the detail
   card closes, so there it is a card in its own right rather than a section
   inside one. */
/* Two copies of this card exist — one in the right column and one in the left
   (.Sub_hide), which is where the description moves in subscribe mode. They are
   never visible at the same time, so both take the same framing. */
.app-shell .product-details .pd-desc-card {
    margin-top: 12px;
    padding: 14px;
    border: 1px solid #ececf0;
    border-radius: 16px;
    background: #fff;
    box-shadow: 0 2px 10px rgba(0, 0, 0, .04);
}

/* No description: the card would be an empty framed box (a blank pill under
   Add To Cart). !important beats the inline display jQuery's .show() writes
   when the page switches between one-time and subscribe mode. */
.app-shell .product-details .pd-desc-card.pd-desc-card--empty {
    display: none !important;
}

/* The left-column copy follows the thumbnail strip rather than another card,
   so it takes the gallery's own bottom spacing. */
/* The left-column copy follows the thumbnail strip, and must take the column's
   full width — as a block in a flex/grid ancestor it was being squeezed to its
   content, which rendered the heading as a narrow vertical sliver beside the
   column gap. */
/* Bottom margin: on a phone the columns stack, and in subscribe mode this card
   is the last thing in the left column — it sat flush against the product card
   that opens the right column, the two frames touching. */
.app-shell .product-details .Sub_hide.pd-desc-card {
    display: block;
    width: 100%;
    min-width: 0;
    margin: 16px 0 14px;
    box-sizing: border-box;
}

.app-shell .product-details .pd-desc-card .product-right-desc {
    margin: 0;
    font-size: 13.5px;
    line-height: 1.6;
    color: var(--app-muted);
}

/* The template's own top border on this paragraph would double the card's. */
.app-shell .product-details .pd-desc-card .border-top-right-des {
    border-top: 0;
    padding-top: 0;
}

.app-shell .pd-desc-title {
    display: flex;
    align-items: center;
    gap: 8px;
    /* The heading fills its card rather than shrink-wrapping to its text — as a
       narrow flex item the label wrapped one character per line. */
    width: 100%;
    min-width: 0;
    margin: 0 0 8px;
    font-size: 14px;
    font-weight: 700;
    line-height: 1.3;
    color: var(--app-ink);
}

/* Keeps a long translation on one line, trimming rather than wrapping to one
   character per line in a narrow column. */
.app-shell .pd-desc-title > span,
.app-shell .pd-desc-title {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.app-shell .pd-desc-title::before {
    content: "";
    flex: 0 0 auto;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--app-theme);
}

.app-shell .pd-desc-body,
.app-shell .pd-desc-body p {
    font-size: 13.5px;
    line-height: 1.6;
    color: var(--app-muted);
}

.app-shell .pd-desc-body p:last-child {
    margin-bottom: 0;
}

/* --- Quantity stepper --------------------------------------------------- */

/* div.pro-qty, not .pro-qty: the subscription panel's <select>s carry that same
   class (address, week, subscription type — see $address_drop_down and
   $subscription_package in the template), and as bare `.pro-qty` this rule
   turned each of them into a 180px flex box, which is why they rendered as
   narrow unstyled stubs beside their labels. */
.app-shell .product-details .def-number-input,
.app-shell .product-details div.pro-qty {
    display: flex;
    align-items: center;
    /* Sized to its contents rather than stretching. width:100% with a 180px cap
       made this a wide bar with the number marooned in the middle and a long
       empty tail before the next control; a stepper should be as wide as its
       three parts and no wider. */
    width: auto;
    max-width: max-content;
    height: 38px;
    margin-bottom: 14px;
    border: 1px solid #e3e5e9;
    border-radius: 10px;
    overflow: hidden;
}

/* Inside the day/quantity table the stepper is a cell's contents, not a field
   in the form stack — its bottom margin was adding to the cell's own padding
   and stretching every day row well past the height its text needs. */
.app-shell .product-details .Sub_show .tabs .def-number-input,
.app-shell .product-details .Sub_show .tabs div.pro-qty {
    margin-bottom: 0;
    /* Centred in its column, as the cells around it are. */
    margin-inline: auto;
}

/* The +/- buttons and the count, sized to match the shorter box. */
.app-shell .product-details .def-number-input .qtybtn,
.app-shell .product-details div.pro-qty .qtybtn,
.app-shell .product-details div.pro-qty .qtybtn_berkely {
    flex: 0 0 34px;
    height: 100%;
}

.app-shell .product-details .def-number-input input,
.app-shell .product-details div.pro-qty input {
    width: 40px;
    min-width: 0;
    height: 100%;
    padding: 0;
    text-align: center;
}

/* Those same selects — and the date picker, which carries .pro-qty too —
   styled as the form controls they are. */
.app-shell .product-details select.pro-qty,
.app-shell .product-details input.pro-qty,
.app-shell .product-details .Sub_show select.form-control {
    display: block;
    width: 100%;
    max-width: none;
    height: 44px;
    padding: 0 34px 0 12px;
    border: 1px solid #e3e5e9;
    border-radius: 10px;
    background-color: #fff;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none'%3E%3Cpath d='M1 1.5L6 6.5L11 1.5' stroke='%236b7280' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 12px center;
    color: var(--app-ink);
    font-family: inherit;
    font-size: 14px;
    font-weight: 500;
    appearance: none;
    -webkit-appearance: none;
}

/* The variant <select> also carries .pro-qty, so the rule above un-hid it and
   it showed as a second picker under the variant tiles. The tiles are the
   control; the select stays only as the value store their click handler sets. */
.app-shell .product-details select.variant-select-native {
    display: none;
}

/* The date field is a text input, not a select — no chevron, and its text runs
   to the normal right inset. */
.app-shell .product-details input.pro-qty {
    padding-right: 12px;
    background-image: none;
}

.app-shell .product-details select.pro-qty:focus,
.app-shell .product-details .Sub_show select.form-control:focus {
    border-color: var(--app-theme);
    box-shadow: 0 0 0 3px var(--app-theme-soft);
    outline: 0;
}

/* --- Subscription panel --------------------------------------------------
   The block the Subscribe button reveals. Its own card, with its fields laid
   out one per line — they were a row of Bootstrap columns sized for a desktop
   width the app frame does not have. */

.app-shell .product-details .Sub_show {
    /* One gap between every block in this panel. The fields come from injected
       rows, the instructions accordion from a Bootstrap .mb-3, the date field
       from its own rule and the summary from another — each had picked its own
       value, which is why the stack read as uneven. They all reference this
       token now, so the rhythm is set in one place. */
    --sub-gap: 16px;
    margin-top: 12px;
    padding: 14px;
    border: 1px solid #ececf0;
    border-radius: 16px;
    background: #fff;
    box-shadow: 0 2px 10px rgba(0, 0, 0, .04);
}

/* Blocks that sit in the panel but outside the injected .row/.col system, each
   of which carried its own margin: the Custom/type buttons, the instructions
   accordion and the panel it opens, and the container-info card. */
.app-shell .product-details .Sub_show .panel-group,
.app-shell .product-details .Sub_show #instructionSection,
.app-shell .product-details .Sub_show .tabs {
    margin-bottom: var(--sub-gap) !important;
}

/* The instructions section's row carries `w-100 pull-right m-0` in the markup.
   w-100 sets width:100% on an element that is ALSO a flex row with Bootstrap's
   negative side gutter, so it measured 100% of the panel plus the gutter and
   broke out past the card's right edge — which is the overflow in the
   screenshot. The float from pull-right is inert here (style2.css, which
   defines it, is not loaded by this layout), so only the width needs fixing.
   Scoped by the id so no other .row on the page is affected. */
.app-shell .product-details #instructionSection,
.app-shell .product-details .row:has(> #instructionSection) {
    float: none;
    width: 100%;
    max-width: 100%;
    margin-inline: 0 !important;
    padding-inline: 0;
}

.app-shell .product-details .Sub_show > h5,
.app-shell .product-details .Sub_show h5 {
    margin: 0 0 12px;
    font-size: 15px;
    font-weight: 700;
    line-height: 1.35;
    color: var(--app-ink);
}

/* Each field arrives in its own injected .row, so the gap between two fields
   was the sum of the row's margin and the column's — which is why the space
   between the selects ran far wider than the 12px intended. The rows carry no
   spacing of their own; the columns below own it. */
.app-shell .product-details .Sub_show .row {
    margin-inline: 0;
    margin-block: 0;
}

.app-shell .product-details .Sub_show .row + .row {
    margin-top: 0;
}

/* The wrapper each select sits in carries its own 12px bottom margin from
   product_detail2.css, which added to the column's and doubled the gap. The
   column owns the spacing; this wrapper is just a box around the field. */
.app-shell .product-details .Sub_show .shoping__cart__table {
    margin-bottom: 0;
}

/* Every field spans the panel: the markup sizes these as col-lg-4 / col-lg-12
   for a desktop three-across row, which inside the app frame left each select
   at a fraction of the width with its label stranded beside it. */
.app-shell .product-details .Sub_show [class*="col-"] {
    flex: 0 0 100%;
    max-width: 100%;
    padding-inline: 0;
    /* One gap for every block in this panel — see --sub-gap below. */
    margin-bottom: var(--sub-gap);
}

/* The Select Week field wraps its label and select in an inner .mb-4.p-0 div.
   That wrapper's own margin collapsed against the column's, so the gap between
   this field and the next was whichever of the two happened to win rather than
   the rhythm set above. Zeroed so the column alone spaces the fields. */
.app-shell .product-details .Sub_show [class*="col-"] > .mb-4,
.app-shell .product-details .Sub_show [class*="col-"] > .mb-3 {
    margin-bottom: 0 !important;
}

/* The last field has the panel's own padding under it. */
.app-shell .product-details .Sub_show .row:last-child > [class*="col-"]:last-child {
    margin-bottom: 0;
}

/* Select Week / Subscription Type / Schedule arrive in a .form-row, whose
   -5px gutter margin is meant to cancel column padding. The columns here have
   none (see above), so the margin alone pulled these fields 5px left of every
   other field in the panel. */
.app-shell .product-details .Sub_show .form-row.select_options {
    margin-inline: 0;
}

/* --- Quantity packages ("Pack of 100 · 99% OFF") ----------------------------
   Selectable tiles. Their desktop styling lives in style2.css, which layout 1
   does not load, so the <label class="package"> fell to the panel's uppercase
   field-label rule above and read as two cramped captions. A grid of cards
   instead; the hidden radio before each label carries the selection. */
.app-shell .product-details .Sub_show .packages.pro_qty_packages {
    grid-template-columns: repeat(auto-fill, minmax(112px, 1fr));
    gap: 10px;
    margin: 0 0 12px;
}

.app-shell .product-details .Sub_show label.package {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 6px;
    height: 100%;
    margin: 0;
    padding: 12px 10px;
    border: 1px solid #dfe3e8;
    border-radius: 12px;
    background: #fff;
    color: var(--app-ink);
    letter-spacing: 0;
    text-align: center;
    text-transform: none;
    cursor: pointer;
    transition: border-color .15s ease, background .15s ease;
}

.app-shell .product-details .Sub_show label.package:hover {
    border-color: var(--app-theme-border, var(--app-theme));
}

.app-shell .product-details .Sub_show .package .package-title {
    font-size: 13.5px;
    font-weight: 700;
    line-height: 1.25;
}

.app-shell .product-details .Sub_show .package .discount {
    display: inline-block;
    padding: 3px 9px;
    border-radius: 999px;
    background: #fdecea;
    color: #c0392b;
    font-size: 11.5px;
    font-weight: 700;
    line-height: 1.3;
}

.app-shell .product-details .Sub_show .pro_qty_package:checked + label.package {
    border-color: var(--app-theme);
    background: var(--app-theme-soft);
    box-shadow: 0 0 0 1px var(--app-theme);
}

/* The "Buy 100 Qty, Get 99% OFF" line under the tiles: icon and text on one
   aligned row, sized as a hint rather than body copy. */
.app-shell .product-details .Sub_show .package_info:not(:empty) {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    margin: 0 0 4px !important;
    padding: 9px 12px;
    border-radius: 10px;
    background: #f6f7f9;
    color: var(--app-ink);
    font-size: 13px;
    line-height: 1.45;
}

.app-shell .product-details .Sub_show .package_info i {
    flex: 0 0 auto;
    margin: 1px 0 0 !important;
    color: var(--app-theme);
    font-size: 15px !important;
}



.app-shell .product-details .Sub_show .primary-btn.typebtn,
.app-shell .product-details .Sub_show .custom-btn {
    min-height: 42px;
    margin-bottom: 0;
    font-size: 13.5px;
}

.app-shell .product-details .Sub_show label {
    display: block;
    margin-bottom: 6px;
    font-size: 11.5px;
    font-weight: 700;
    letter-spacing: .04em;
    line-height: 1.2;
    text-transform: uppercase;
    color: var(--app-muted);
}

/* --- Daily / Alternate / Custom / Nth Day --------------------------------
   The tabs arrive as one .form-row of col-lg-3/4 columns, but the full-width
   column rule above (`[class*="col-"] { flex: 0 0 100% }`) stacked them into
   three tall bars. One equal-width row instead, styled as a segmented choice
   like the One-Time / Subscribe toggle above it: outlined when idle, tinted
   with the theme when selected (.active is what the page's JS toggles). */
.app-shell .product-details .Sub_show .form-row.option_hide {
    display: flex;
    flex-wrap: nowrap;
    gap: 8px;
    margin: 0 0 var(--sub-gap);
}

.app-shell .product-details .Sub_show .form-row.option_hide > .subs_type_tab {
    flex: 1 1 0;
    min-width: 0;
    max-width: none;
    margin-bottom: 0;
    padding: 0;
}

.app-shell .product-details .Sub_show .subs_type_tab .primary-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    /* A fixed height, and the padding and border forced: the shared
       product_detail.css gives .altername-btn `padding: 14px 0 !important` and
       every .disbale_button_color a theme-coloured `border … !important`, so
       Alternate rendered taller than Daily/Custom and all three looked active. */
    height: 42px;
    min-height: 42px;
    margin: 0;
    padding: 0 8px !important;
    border: 1px solid #dfe2e7 !important;
    border-radius: 10px;
    background: #fff !important;
    color: var(--app-ink) !important;
    font-size: 13.5px;
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    transition: border-color .15s ease, background-color .15s ease, color .15s ease;
}

.app-shell .product-details .Sub_show .subs_type_tab .primary-btn:hover {
    border-color: var(--app-theme) !important;
}

.app-shell .product-details .Sub_show .subs_type_tab .primary-btn.active {
    border-color: var(--app-theme) !important;
    background: var(--app-theme-soft, #eef3f8) !important;
    color: var(--app-theme) !important;
    font-weight: 700;
}

/* --- Payment methods -----------------------------------------------------
   Each gateway is .box-radio > label.balance_card > radio + logo + name. Two
   things broke it: the label rule above made the gateway name an 11.5px grey
   uppercase caption, and Bootstrap's .form-check-input is absolutely
   positioned with a negative margin, so the radio hung outside the card with
   the logo floating above the name. The card is now one flex row — radio,
   logo, name, and the wallet balance pushed to the right. */
.app-shell .product-details .payment_option .box-radio {
    width: 100% !important;
    margin: 0 0 8px !important;
    padding: 0 !important;
    border: 0 !important;
    background: transparent !important;
    box-shadow: none !important;
}

/* Only the very last card loses its gap. Pre-pay gateways (Razorpay…) and
   post-pay ones (Wallet, COD) arrive in two separate wrappers from
   CustomHelper::paymentGatewayUI(), so a plain .box-radio:last-child matched
   the last card of EACH wrapper — Razorpay included — and the Wallet card sat
   flush against it with no gap. */
.app-shell .product-details .payment_option .text-left > :last-child > .box-radio:last-child,
.app-shell .product-details .payment_option > div > .box-radio:last-child {
    margin-bottom: 0 !important;
}

.app-shell .product-details .payment_option .box-radio label.form-check-label {
    display: flex !important;
    align-items: center;
    gap: 12px;
    width: 100%;
    min-height: 56px;
    margin: 0;
    padding: 10px 14px;
    border: 1px solid #e3e5e9;
    border-radius: 12px;
    background: #fff;
    font-size: 14px;
    font-weight: 600;
    letter-spacing: 0;
    line-height: 1.35;
    text-transform: none;
    color: var(--app-ink);
    cursor: pointer;
    /* The shared product_detail.css gives every card a drop shadow; on the flat
       app cards it read as one card overlapping the next. */
    box-shadow: none;
    transition: border-color .15s ease, background-color .15s ease;
}

.app-shell .product-details .payment_option .box-radio label.form-check-label:hover {
    border-color: var(--app-theme);
}

.app-shell .product-details .payment_option .box-radio label.form-check-label:has(.payment_method:checked) {
    border-color: var(--app-theme);
    background: var(--app-theme-soft, #eef3f8);
}

.app-shell .product-details .payment_option .box-radio .form-check-input {
    position: static;
    flex: 0 0 18px;
    width: 18px;
    height: 18px;
    margin: 0;
    accent-color: var(--app-theme);
    cursor: pointer;
}

.app-shell .product-details .payment_option .box-radio label img {
    flex: 0 0 auto;
    width: 32px;
    height: 32px;
    max-height: none !important;
    margin: 0 !important;
    padding: 2px;
    border: 1px solid #eceef1;
    border-radius: 50%;
    background: #fff;
    object-fit: contain;
}

/* Wallet balance — the page's JS rewrites it, so only the placement is set. */
.app-shell .product-details .payment_option .box-radio .update_wallet {
    margin-left: auto;
    font-weight: 700;
    color: var(--app-theme);
}

/* "Select Payment Method" heading over the cards. */
.app-shell .product-details .payment_option .select-pay-label {
    margin-bottom: 8px;
}

/* Radio at the right end of each card: logo, name, (wallet balance), radio.
   Explicit `order` values, so the radio lands last whatever the source order
   or any inherited ordering, and its auto margin pushes it to the card's right
   edge. When a wallet balance is present the balance takes the auto margin and
   the radio follows it at the normal gap. Scoped to .product-details, where
   .box-radio is only used for payment methods. The logo and the (unwrapped)
   name text keep the default order 0, so they stay in source order. */
.app-shell .product-details .box-radio label.form-check-label .update_wallet {
    order: 2;
    margin-left: auto;
}

.app-shell .product-details .box-radio label.form-check-label .form-check-input {
    order: 3;
    position: static;
    flex: 0 0 18px;
    width: 18px;
    height: 18px;
    margin: 0 0 0 auto;
    accent-color: var(--app-theme);
    cursor: pointer;
}

.app-shell .product-details .box-radio label.form-check-label:has(.update_wallet) .form-check-input {
    margin-left: 0;
}

/* --- Day / quantity table -----------------------------------------------
   The per-day schedule the Custom button reveals. It arrives from the page's
   JS with no layout of its own beyond a 5px cell padding, so the headers ran
   together ("Price Per Day Delivery Charges") and the cells did not line up
   under them. */

.app-shell .product-details .Sub_show .tabs table {
    width: 100%;
    margin: 0;
    /* fixed so the columns below hold their widths instead of being sized by
       whichever day name or price happens to be longest. */
    table-layout: fixed;
    border-collapse: collapse;
}

/* `table th`, not bare `th`: product_detail.css's
   `.row.address_hide.remove_onchange_address .shoping__cart__table th` has the
   same weight and is linked later in the page, so its 10px 16px padding and
   white-space:nowrap won — the headers overflowed their fixed-width columns,
   ran into each other and "Delivery Charges" was clipped at the table edge. */
.app-shell .product-details .Sub_show .tabs table th,
.app-shell .product-details .Sub_show .tabs table td {
    padding: 8px 6px;
    border-bottom: 1px solid #f1f2f4;
    text-align: center;
    vertical-align: middle;
    font-size: 12px;
    line-height: 1.3;
    word-break: normal;
}

.app-shell .product-details .Sub_show .tabs table th {
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: .03em;
    text-transform: uppercase;
    color: var(--app-muted);
    white-space: normal;
}

/* Day name leads the row, so it is the one column read left-aligned. */
.app-shell .product-details .Sub_show .tabs th:first-child,
.app-shell .product-details .Sub_show .tabs td:first-child {
    width: 22%;
    text-align: left;
    font-weight: 600;
    color: var(--app-ink);
}

/* Quantity gets the room the stepper needs; the two money columns split the
   rest evenly so each sits under its own heading. */
.app-shell .product-details .Sub_show .tabs th:nth-child(2),
.app-shell .product-details .Sub_show .tabs td:nth-child(2) {
    width: 30%;
}

.app-shell .product-details .Sub_show .tabs th:nth-child(3),
.app-shell .product-details .Sub_show .tabs td:nth-child(3),
.app-shell .product-details .Sub_show .tabs th:nth-child(4),
.app-shell .product-details .Sub_show .tabs td:nth-child(4) {
    width: 24%;
    font-weight: 600;
    color: var(--app-ink);
}

.app-shell .product-details .Sub_show .tabs tbody tr:last-child th,
.app-shell .product-details .Sub_show .tabs tbody tr:last-child td {
    border-bottom: 0;
}

/* The stepper inside a cell is smaller than the one in the main card and must
   not carry that one's bottom margin or 180px floor. */
.app-shell .product-details .Sub_show .tabs td .quantity > div.pro-qty {
    display: inline-flex;
    width: auto;
    max-width: none;
    height: 32px;
    margin: 0;
    vertical-align: middle;
}

.app-shell .product-details .Sub_show .tabs td .quantity > div.pro-qty .qtybtn,
.app-shell .product-details .Sub_show .tabs td .quantity > div.pro-qty .qtybtn_berkely {
    flex: 0 0 30px;
}

/* .days_quantity / .all_quantity are the classes these inputs carry — not the
   .number-ip the main card's stepper uses — so they need naming here to pick up
   the borderless centred treatment. */
.app-shell .product-details .Sub_show .tabs td .quantity > div.pro-qty input,
.app-shell .product-details .Sub_show .tabs .days_quantity,
.app-shell .product-details .Sub_show .tabs .all_quantity {
    flex: 0 0 auto;
    width: 34px;
    height: 100%;
    padding: 0;
    border: 0;
    outline: 0;
    background: transparent;
    text-align: center;
    font-family: inherit;
    font-size: 13px;
    font-weight: 600;
    color: var(--app-ink);
    -webkit-text-fill-color: var(--app-ink);
    opacity: 1;
}

/* The tooltip glyph beside a delivery charge sits on the figure's baseline
   rather than starting a second line. */
.app-shell .product-details .Sub_show .tabs td .fa-question-circle,
.app-shell .product-details .Sub_show .tabs td [data-toggle="tooltip"] {
    margin-left: 4px;
    color: var(--app-muted);
    font-size: 11px;
}

/* The wrapper the full-week table sits in draws its own frame; inside the
   panel card that reads as a box in a box. */
.app-shell .product-details .Sub_show .border-radius-wrap {
    border: 0;
    padding: 0;
}

/* --- Container information ----------------------------------------------
   The deposit/rental table the JS injects when a product carries containers.
   It arrives as a Bootstrap .alert with an unstyled table inside, so without
   these rules the heading, the four columns and the note all ran at their own
   widths and none of the figures lined up under their headers. */

.app-shell .product-details .container_detail {
    display: block;
    margin: 0 0 12px;
}

/* Delivery Start Date follows the container card directly; give its label
   room so it does not sit on the card's bottom edge. */
.app-shell .product-details .select_options .datepicker_error {
    padding-top: 12px;
}

.app-shell .product-details .container_detail .alert-custom {
    width: 100%;
    max-width: 100%;
    margin: 0;
    padding: 12px;
    border: 1px solid #eceef1;
    border-radius: 12px;
    background: #f8f9fb;
}

/* The heading rides in a <span><b style="font-size:18px"> — the inline size is
   why it has to be named here to come down to the panel's scale. */
.app-shell .product-details .container_detail .alert-custom > span > b {
    display: block;
    margin-bottom: 10px;
    font-size: 14px !important;
    font-weight: 700;
    line-height: 1.3;
    color: var(--app-ink);
}

/* table-layout: auto, not fixed: the three figure columns shrink to their
   content and the name takes everything left, rather than each getting a fixed
   share that wrapped a short name like "Damage Deposit / Cooler cleaning fee"
   while the figures sat in wide empty cells. */
.app-shell .product-details .container_detail table.table {
    width: 100%;
    margin: 0;
    table-layout: auto;
    /* separate, so the border-radius below actually rounds the corners. */
    border-collapse: separate;
    background: #fff;
    border: 1px solid #eceef1;
    border-radius: 10px;
    border-spacing: 0;
    overflow: hidden;
}

.app-shell .product-details .container_detail table.table th,
.app-shell .product-details .container_detail table.table td {
    padding: 9px 10px;
    border: 0;
    border-bottom: 1px solid #eceef1;
    text-align: right;
    vertical-align: middle;
    font-family: inherit;
    font-size: 13px;
    line-height: 1.4;
    color: var(--app-ink);
}

.app-shell .product-details .container_detail table.table thead th {
    background: #f3f4f7;
}

.app-shell .product-details .container_detail table.table th {
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: .03em;
    text-transform: uppercase;
    color: var(--app-muted);
    white-space: normal;
}

/* The name is the row's label, so it leads left; the three figures line up
   right under their own headers. */
.app-shell .product-details .container_detail table.table th:first-child,
.app-shell .product-details .container_detail table.table td:first-child {
    width: auto;
    text-align: left;
    word-break: break-word;
}

.app-shell .product-details .container_detail table.table td:first-child {
    font-weight: 600;
}

/* width: 1% + nowrap is the shrink-to-content idiom under table-layout: auto. */
.app-shell .product-details .container_detail table.table th:not(:first-child),
.app-shell .product-details .container_detail table.table td:not(:first-child) {
    width: 1%;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

.app-shell .product-details .container_detail table.table td:last-child {
    font-weight: 700;
}

.app-shell .product-details .container_detail table.table tbody tr:last-child td {
    border-bottom: 0;
}

/* The builder puts <input type="hidden"> directly inside <tr>, which is not
   valid there — the browser hoists them out of the table and they can end up
   as stray inline boxes. Taking them out of the flow keeps the row clean. */
.app-shell .product-details .container_detail input[type="hidden"] {
    display: none !important;
}

/* The note under the table. It arrives as a nested .alert-warning inside a
   themed span, which drew a second coloured box inside the panel. */
.app-shell .product-details .container_detail .alert-warning {
    display: flex;
    align-items: flex-start;
    gap: 6px;
    margin: 10px 0 0;
    padding: 0;
    border: 0;
    border-radius: 0;
    background: none;
    color: var(--app-muted);
    font-size: 11.5px;
    line-height: 1.45;
}

.app-shell .product-details .container_detail .alert-warning strong {
    flex: 0 0 auto;
    font-weight: 400;
}

/* position:relative for the glyph pseudo-elements below. The markup renders
   these as EMPTY spans (`<span class="dec qtybtn"></span>`), so without drawn
   glyphs the stepper was a blank grey box — which is what it looked like on the
   page. Same construction as the cart and product-grid steppers. */
/* font-size: 0 so ONLY the drawn bars below show. These spans are empty in the
   page's own markup but the injected subscription tables put whitespace and
   entities inside some of them, which rendered alongside the bars and made the
   minus read as "=" and the plus as a double-barred glyph. */
/* .qtybtn_berkely is the same stepper button on product_detail2's
   "Add Quantity" (Once / Weekly Order) table — a different class so its own
   click handler binds, but it needs the same drawn glyphs or it renders as two
   empty boxes. */
/* width/min-width as well as flex-basis: the wrapper is sized to max-content,
   and Safari (WebKit) measures a flex item's contribution to that from its
   width / content — NOT its flex-basis. These spans are empty, so in Safari
   they counted as 0px, the wrapper shrank to just the input, and overflow:
   hidden clipped the − and + away. Chrome uses the basis, which is why it
   only showed up on Safari / iOS. */
.app-shell .product-details .qtybtn,
.app-shell .product-details .qtybtn_berkely {
    position: relative;
    display: block;
    flex: 0 0 38px;
    width: 38px;
    min-width: 38px;
    height: 100%;
    border: 0;
    background: #f6f7f9;
    color: transparent;
    font-size: 0;
    line-height: 0;
    text-align: center;
    cursor: pointer;
    user-select: none;
}

.app-shell .product-details .qtybtn:hover,
.app-shell .product-details .qtybtn_berkely:hover {
    background: #eceef1;
}

/* Horizontal bar — on both buttons, so it reads as the minus sign. */
.app-shell .product-details .qtybtn::before,
.app-shell .product-details .qtybtn_berkely::before {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 11px;
    height: 2px;
    border-radius: 2px;
    background: var(--app-ink);
}

/* Vertical bar — only on .inc, crossing the bar above to make a plus. */
.app-shell .product-details .qtybtn.inc::after,
.app-shell .product-details .qtybtn_berkely.inc::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 2px;
    height: 11px;
    border-radius: 2px;
    background: var(--app-ink);
}

/* .number-ip / .pro-qty input, not .main_qty: that class is on the WRAPPER
   div, so the old rule styled the container and never reached the field —
   the input kept its browser default and rendered as a wide bare box beside
   the buttons. */
.app-shell .product-details .qty-txt,
.app-shell .product-details .def-number-input input,
.app-shell .product-details div.pro-qty input,
.app-shell .product-details .number-ip {
    flex: 1 1 auto;
    min-width: 0;
    width: 44px;
    height: 100%;
    padding: 0;
    border: 0;
    outline: 0;
    background: transparent;
    text-align: center;
    font-family: inherit;
    font-size: 15px;
    font-weight: 600;
    color: var(--app-ink);
    /* The field is rendered `disabled` (the +/- buttons drive it), and a
       disabled input greys out on iOS — the value has to stay readable. */
    -webkit-text-fill-color: var(--app-ink);
    opacity: 1;
    -moz-appearance: textfield;
}

/* No spinner arrows: the +/- buttons are the control. */
.app-shell .product-details .number-ip::-webkit-outer-spin-button,
.app-shell .product-details .number-ip::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

.app-shell .price-breakdown-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
    padding: 7px 0;
    border-bottom: 1px solid #f1f2f4;
    font-size: 14px;
}

.app-shell .price-breakdown-row:last-child {
    border-bottom: 0;
}

.app-shell .price-label {
    color: var(--app-muted);
}

.app-shell .price-amount-bold {
    font-weight: 700;
    color: var(--app-ink);
}

.app-shell .price-extra,
.app-shell .extra-price-wrapper {
    font-size: 13px;
    color: var(--app-muted);
}

/* The wrapper is an inline-block carrying Bootstrap's ml-auto in the markup,
   which pushed the stepper to the right edge of the card. Block-level and
   left-aligned so the control starts under its label. */
.app-shell .product__details__text .pd-field-qty .product__details__quantity {
    display: block !important;
    width: 100%;
    margin-left: 0 !important;
}

/* A compact control sized to its three parts, NOT stretched across the card.
   At full width the value sat marooned in the middle with the − and + pushed
   to opposite edges, which read as three separate controls rather than one. */
.app-shell .product__details__text .pd-field-qty .pro-qty.main_qty {
    width: auto !important;
    margin: 0 !important;
    justify-content: flex-start !important;
}

.app-shell .product__details__text .pd-field-qty .pro-qty.main_qty .qtybtn {
    flex: 0 0 42px;
    width: 42px;
    min-width: 42px;
}

/* The value takes only the room a two- or three-digit quantity needs, rather
   than absorbing all the space left between the buttons. */
.app-shell .product__details__text .pd-field-qty .pro-qty.main_qty .number-ip {
    flex: 0 0 auto;
    width: 52px;
    min-width: 0;
}

.app-shell .product-detail-action-buttons {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 14px;
}

/* The two actions share the row rather than stacking, as in the reference.
   These are Bootstrap columns in the markup, so their grid widths and padding
   are cleared and the flex row above does the sizing. */
.app-shell .product-detail-action-buttons > [class*="col-"] {
    flex: 1 1 0;
    min-width: 0;
    max-width: none;
    padding: 0;
}

/* The buttons carry a bottom margin for the stacked case; in the row the
   group's own margin closes it. */
.app-shell .product-detail-action-buttons .primary-btn {
    margin-bottom: 0;
}

/* --- Primary actions ---------------------------------------------------- */

/* .detail-btn-wrap is the Subscribe button's class in product_detail2 — it does
   NOT carry .primary-btn there, so without it that button rendered as a bare
   underlined link. */
.app-shell .product-details .site-btn,
.app-shell .product-details .primary-btn,
.app-shell .product-details .detail-btn-wrap,
.app-shell .product-details .combobtn,
.app-shell .product-details .custom-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    width: 100%;
    min-height: 48px;
    margin-bottom: 10px;
    padding: 12px 16px;
    border: 0;
    border-radius: 12px;
    background: var(--app-theme);
    color: #fff;
    font-size: 15px;
    font-weight: 700;
    text-align: center;
    text-decoration: none;
    cursor: pointer;
}

.app-shell .product-details .btn-primary {
    background: var(--app-theme);
    border-color: var(--app-theme);
}

/* Subscribe is the secondary action: outlined, not a second solid block.
   Two identical filled buttons stacked gave the page no hierarchy — Add To
   Cart is the primary path and should be the only filled control. */
.app-shell .product-details .primary-btn.subscribe,
.app-shell .product-details .detail-btn-wrap.subscribe {
    background: transparent;
    color: var(--app-theme);
    box-shadow: inset 0 0 0 1.5px var(--app-theme);
}

.app-shell .product-details .primary-btn.subscribe:hover,
.app-shell .product-details .detail-btn-wrap.subscribe:hover {
    background: var(--app-theme-soft);
}

.app-shell .typebtn,
.app-shell .nth-btn,
.app-shell .alternate_day_btn,
.app-shell .checkbox-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 1 1 auto;
    width: auto;
    min-height: 40px;
    margin-bottom: 0;
    padding: 9px 12px;
    border: 1px solid #e4e6ea;
    border-radius: 10px;
    background: #fff;
    color: var(--app-ink);
    font-size: 13px;
    font-weight: 600;
    text-align: center;
    cursor: pointer;
}

/* .active marks the chosen pattern (set by the template's own JS). */
.app-shell .typebtn.active,
.app-shell .nth-btn.active,
.app-shell .alternate_day_btn.active,
.app-shell .checkbox-btn.active {
    background: var(--app-theme);
    border-color: var(--app-theme);
    color: #fff;
}

.app-shell .nth-qty-btn,
.app-shell .icon-sm-btn {
    min-width: 38px;
    min-height: 38px;
    border: 1px solid #e4e6ea;
    border-radius: 9px;
    background: #fff;
    cursor: pointer;
}

/* --- Container deposit table ------------------------------------------- */

.app-shell .item-table {
    width: 100%;
    margin-bottom: 14px;
    border-collapse: collapse;
    font-size: 13px;
}

.app-shell .item-table th,
.app-shell .item-table td {
    padding: 8px 6px;
    border-bottom: 1px solid #f1f2f4;
    text-align: left;
}

.app-shell .item-table th {
    color: var(--app-muted);
    font-weight: 600;
}

/* --- Order summary card ------------------------------------------------- */

/* :not(:empty) — renderOrderSummary() fills this only when the API returns a
   summary, so unqualified the card drew an empty bordered box under the
   subscribe panel whenever it did not. That is the stray rounded strip that
   appeared between the summary text and the Add Credit Card button.
   The side margin goes with it: inside the subscribe panel this card sits in a
   column that is already padded, so --app-pad on each side inset it from the
   summary and totals it sits between rather than lining up with them. */
.app-shell .order-summary-card:has(*) {
    margin: 0 0 18px;
    padding: 16px;
    border: 1px solid #ececf0;
    border-radius: 16px;
    background: #fff;
}

/* --- Delivery start date ------------------------------------------------
   The block is injected by JS (see the date_picker_t template in
   Slugs/v1/product_detail.php), so it arrives with no spacing of its own and
   its label butted straight against the Container Information card above it. */

/* The same --sub-gap every other block in the panel takes. This was 26px to
   clear the Container Information card above it, but that made the date field
   the one item in the stack with a different gap — the unevenness shows most
   here because the blocks either side of it are evenly spaced. */
.app-shell .berkely_box .remove_onchange_address {
    margin-top: var(--sub-gap, 16px);
}

.app-shell .berkely_box .remove_onchange_address > label {
    display: block;
    margin-bottom: 6px;
    font-size: 11.5px;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--app-muted);
}

/* The injected column carries Bootstrap's gutter, which pushed the field past
   the panel's padding on both edges. */
.app-shell .berkely_box .datepicker_error {
    padding-inline: 0;
}


/* --- Subscribe summary + totals -----------------------------------------
   Both blocks are injected by JS (.summary and .deliveryTotals in
   Slugs/v1/product_detail.php), so they arrive with no styling and render at
   the body's default size — the summary ran as a wall of 15px prose and the
   totals as flat rows with no separation from it. */

/* The summary is explanatory copy, not content the customer acts on: smaller
   and set apart, so it reads as a note beside the figures rather than
   competing with them.

   Cream/gold rather than the neutral grey it carried: the same #fdf6e3 on
   #6b4c12 pair the header's announcement strip uses (app-mobile.css, around
   .app-header-utility) and the delivery-charges note on this page. Reusing
   that pair keeps "this is guidance, not a control" saying the same thing
   wherever it appears, rather than inventing a third notice colour. */
/* Card-verification note under "Verify your linked payment method" (TMC61).
   Its wrapper is `.submit-container.text-right`, so it rendered as loose,
   right-aligned copy. Same cream notice as the summary below, left-aligned,
   spanning the column like the button above it. */
.app-shell .product-details .submit-container:has(> .sage_note) {
    width: 100%;
    max-width: none;
    padding: 0 !important;
    text-align: left !important;
}

.app-shell .product-details .sage_note {
    display: block;
    margin: 12px 0 0 !important;
    padding: 12px 16px;
    border: 1px solid #f2e2bf;
    border-radius: 10px;
    background: #fdf6e3;
    color: #6b4c12;
    font-size: 12.5px;
    line-height: 1.55;
    text-align: left;
}

.app-shell .product-details .sage_note b {
    font-weight: 700;
    color: #6b4c12;
}

.app-shell .berkely_box .summary,
.app-shell .subscribe_box .summary,
.app-shell .summary:not(:empty) {
    display: block;
    /* No margin-top, for the same reason as .price_calculate below: the block
       above this one is a col-lg-12 and already contributes --sub-gap beneath
       itself. Adding it again here doubled the gap. The column rule gives this
       block its own bottom gap as usual. */
    margin-top: 0;
    /* !important because .summary is itself a `col-lg-12` in the markup, and
       the `.Sub_show [class*="col-"] { padding-inline: 0 }` rule above — which
       every other field needs — was stripping the side padding straight back
       off this one, leaving the copy flush against the tint's edges. */
    padding: 14px 16px !important;
    border: 1px solid #f2e2bf;
    border-radius: 10px;
    background: #fdf6e3;
    font-size: 12.5px;
    line-height: 1.6;
    color: #6b4c12;
    /* The day list arrives as "Monday,Tuesday,…" with no spaces, one unbreakable
       word wider than the card, so it ran out past the right edge. The template's
       .text-break is a Bootstrap utility this layout does not load. */
    overflow-wrap: anywhere;
}

/* The "Summary:" label and the bold figures inside the sentence. A deeper shade
   of the same brown rather than --app-ink: near-black on cream reads as a
   different element dropped into the notice, where this stays part of it. */
.app-shell .summary:not(:empty) b,
.app-shell .summary:not(:empty) strong {
    font-weight: 700;
    color: #4a340c;
}

/* --- Totals -------------------------------------------------------------- */

/* A panel of its own, so the figures read as a block rather than as more of
   the summary text above them. */
/* :has(*) rather than :not(:empty). :empty only matches an element with NO
   child nodes at all — a single space or newline between the injected tags is
   enough to defeat it, which is why the gate did not catch this container.
   :has(*) requires a real child ELEMENT, so the card is drawn only once the
   totals rows are actually in place. */
.app-shell .deliveryTotals:has(*) {
    display: block;
    margin-top: 16px;
    /* !important: .deliveryTotals is a col-lg-12, and the `.Sub_show [class*="col-"]
       { padding-inline: 0 }` rule out-ranks this one — same fix as .summary
       above. Without it the labels sat flush against the card border. */
    padding: 12px 16px !important;
    border: 1px solid #ecedf0;
    border-radius: 12px;
    background: #fff;
}

/* Belt and braces: with no rows the container contributes nothing at all, so
   an empty one cannot leave a gap between the summary and the button either. */
.app-shell .deliveryTotals:not(:has(*)),
.app-shell .price_calculate:not(:has(*)),
.app-shell .order-summary-card:not(:has(*)),
.app-shell .deliveryCharges:not(:has(*)) {
    display: none !important;
}

/* Each injected row is a .d-flex.justify-content-between pair. The inline
   `border-top: 1px dashed #ddd` some of them carry is replaced with the sheet's
   own hairline so every row matches. */
.app-shell .deliveryTotals > div {
    align-items: baseline;
    gap: 12px;
    margin-bottom: 0 !important;
    /* !important: the Delivery Charge row carries Bootstrap .pt-2. */
    padding: 8px 0 !important;
    border-top: 0 !important;
    font-size: 13px;
    color: var(--app-muted);
}

.app-shell .deliveryTotals > div + div {
    border-top: 1px solid #f3f4f6 !important;
}

/* The amount side of each row. */
.app-shell .deliveryTotals > div > span:last-child {
    flex: 0 0 auto;
    font-weight: 600;
    color: var(--app-ink);
    white-space: nowrap;
}

/* The final row (Total Amount / Grand Total) carries a <b> in the label —
   using that as the hook rather than :last-child, which would also catch a
   trailing note row. */
.app-shell .deliveryTotals > div:has(> b) {
    margin-top: 2px;
    padding-top: 10px !important;
    border-top: 1px solid #ecedf0 !important;
    font-size: 15px;
}

.app-shell .deliveryTotals > div:has(> b) > b {
    font-weight: 800;
    color: var(--app-ink);
}

.app-shell .deliveryTotals > div:has(> b) > span:last-child {
    font-size: 16px;
    font-weight: 800;
    color: var(--app-theme);
}

/* Section captions the API sends inside this block ("Tax Details"), which
   arrive as plain bold text on their own line. */
.app-shell .deliveryTotals > b,
.app-shell .deliveryTotals > strong {
    display: block;
    margin: 10px 0 2px;
    font-size: 11.5px;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--app-muted);
}

/* --- Subscribe totals (.price_calculate) --------------------------------
   Slugs/v1/product_detail2.php injects this block (the `price_total` template
   around line 5179). Note it is NOT .deliveryTotals — that container belongs to
   product_detail.php, and its rules above do not reach this page.

   The rows here are plain <div>s with a `float: right` <span> for the amount,
   not flex pairs, so each row is styled as a block with an overflow hidden to
   contain the float. */

/* :not(:empty) — the container is rendered with the panel and only filled once
   the totals AJAX returns, so unqualified it drew an empty bordered box under
   the summary while the request was in flight (and permanently on a product
   whose totals never load). */
.app-shell .price_calculate:has(*) {
    /* No margin-top. The summary above is a col-lg-12 and already contributes
       --sub-gap below itself; adding the same again here made this the one
       double gap in the stack (32px against everything else's 16). The column
       rule supplies the bottom gap as usual. */
    margin-top: 0;
    /* Side padding matches the summary box's 16px, and !important for the same
       reason that rule needs it: this is a `col-lg-12`, and the
       `.Sub_show [class*="col-"] { padding-inline: 0 }` rule would otherwise
       strip the sides off and leave the figures flush to the border. */
    padding: 14px 16px !important;
    border: 1px solid #ecedf0;
    border-radius: 12px;
    background: #fff;
}

/* The template opens with an <hr>; the card's own top edge replaces it. */
.app-shell .price_calculate > hr {
    display: none;
}

/* Each row. overflow:hidden contains the floated amount so consecutive rows
   cannot collapse into each other. */
.app-shell .price_calculate > div {
    overflow: hidden;
    margin-bottom: 0 !important;
    padding: 7px 0;
    font-size: 13px;
    line-height: 1.5;
    color: var(--app-muted);
}

.app-shell .price_calculate > div + div {
    border-top: 1px solid #f3f4f6;
}

/* The amount on every row. */
.app-shell .price_calculate span[style*="float"] {
    font-weight: 600;
    color: var(--app-ink);
    white-space: nowrap;
}

/* "Subscription Total" — the first row's label is a <b>. */
.app-shell .price_calculate > div > b {
    font-weight: 700;
    color: var(--app-ink);
}

/* --- Tax details group --------------------------------------------------- */

/* The tax rows are wrapped in their own div, so the group is set apart as a
   sub-section rather than reading as three more top-level rows. */
.app-shell .price_calculate .taxes-summary-wrap {
    overflow: hidden;
    margin: 4px 0;
    padding: 10px 12px;
    border-top: 1px solid #f3f4f6;
    border-radius: 8px;
    background: #fafbfc;
}

/* "Tax Details" caption. */
.app-shell .price_calculate .taxes-summary-wrap > div:first-child b {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--app-muted);
}

.app-shell .price_calculate .taxes-summary-wrap > div {
    overflow: hidden;
    margin-bottom: 0 !important;
    padding: 4px 0;
    border: 0;
    font-size: 12.5px;
}

/* --- Total amount -------------------------------------------------------- */

/* The final row is an <h5>. The markup floats its amount at an inline 20px
   with its own font-weight, which this leaves alone — only the row around it
   is given the emphasis and separation it was missing. */
.app-shell .price_calculate h5 {
    overflow: hidden;
    margin: 0;
    padding-top: 10px;
    border-top: 1px solid #ecedf0;
    font-size: 15px;
    font-weight: 800;
    color: var(--app-ink);
}

/* The <h5> sits inside a row <div> that carries the 7px block padding set
   above. With the heading's own padding on top of it the card ended on a deep
   band of empty space below Total Amount. */
.app-shell .price_calculate > div:last-child {
    padding-bottom: 0;
}

.app-shell .price_calculate h5 span[style*="float"] {
    color: var(--app-theme);
}

/* --- Delivery instructions ----------------------------------------------
   The accordion header and the panel it opens. Neither had any layout-1 rules,
   so both rendered as the desktop sheet's flat grey blocks — heavier than the
   fields around them and inset by their own Bootstrap padding. */

.app-shell .instruction-accordion {
    border: 1px solid #ececf0;
    border-radius: 10px;
    background: #fff;
    overflow: hidden;
}

.app-shell .instruction-accordion .panel-heading {
    padding: 0;
    border: 0;
    background: #fafbfc;
}

/* The header is the toggle: pencil, label, and the +/- on the far right.
   a#addInstruction too: the shared product_detail.css styles it by id (16px,
   800, theme colour, grey fill), which out-ranked the class alone, so the
   header was the largest text in the panel. 14px matches the field values. */
.app-shell .instruction-accordion .instructionBtn,
.app-shell .instruction-accordion a#addInstruction {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 11px 14px;
    background: transparent;
    color: var(--app-ink);
    font-size: 14px;
    font-weight: 600;
    line-height: 1.35;
    text-decoration: none !important;
}

.app-shell .instruction-accordion .instructionBtn i {
    color: var(--app-theme);
    font-size: 12px;
}

.app-shell .instruction-accordion .panel-body {
    margin: 0 !important;
    padding: 12px 14px 14px;
    border-top: 1px solid #f1f2f4;
}

/* Open / closed. Bootstrap's collapse relied on bootstrap.min.css for its
   .collapse / .show rules, which layout 1 does not load — so the panel was
   always open and the header did nothing. The page's own handler toggles
   .is-open on the panel and .collapsed on the header (which drives the +/−). */
.app-shell .instruction-accordion .panel-collapse {
    display: none;
}

.app-shell .instruction-accordion .panel-collapse.is-open {
    display: block;
}

.app-shell .instruction-accordion .instructionBtn {
    cursor: pointer;
    user-select: none;
}

/* The +/− the desktop sheet draws after the header: theme coloured, pinned to
   the right edge, and the same glyph size whichever state it is in. */
.app-shell .instruction-accordion .panel-heading a:after,
.app-shell .instruction-accordion .panel-heading a.collapsed:after {
    float: none;
    margin-left: auto;
    color: var(--app-theme);
    font-size: 20px;
    font-weight: 600;
    line-height: 1;
}

/* The inner wrapper carries .mb-3/.mt-0 utilities and a grey fill from the
   desktop sheet; the panel body above already frames this. */
.app-shell .product-details .ins-reason-section {
    margin: 0 !important;
    padding: 0;
    background: none;
    border: 0;
}

.app-shell .product-details .ins-reason-section label {
    margin-bottom: 6px !important;
}

/* The textarea the "Other" option reveals. */
.app-shell .product-details .other-instruction {
    min-height: 74px;
    margin-top: 10px !important;
    padding: 9px 12px;
    border: 1px solid #e3e5e9;
    border-radius: 10px;
    font-size: 13.5px;
    resize: vertical;
}
