

.app-shell {
    /* Page-local tokens, so the card treatment is stated once. */
    --cart-surface: #fff;
    --cart-line: #ecedf0;
    --cart-line-soft: #f3f4f6;
    --cart-radius: 16px;
    --cart-radius-sm: 10px;
    --cart-shadow: 0 1px 2px rgba(16, 24, 40, .04);
    --cart-shadow-lift: 0 6px 20px rgba(16, 24, 40, .08);
    --cart-danger: #dc2626;
    --cart-danger-soft: #fef2f2;
    --cart-danger-line: #fecaca;
    --cart-success: #15803d;
    --cart-gap: 14px;
    --cart-aside-width: 336px;
    --cart-split-gap: 20px;
    --cart-head-height: 27px;
    --cart-head-gap: 10px;
}


.app-shell .cart-container {
    width: 100%;
    max-width: 100%;
    padding-inline: var(--app-pad);
    /* A page-level container must never create its own scroll axis: the
       sticky summary below depends on an unbroken ancestor chain. */
    overflow: visible;
}

.app-shell .cart-top-30px {
    /* .spad on the same element is the desktop theme's 70px section padding —
       hence !important, which the shared rhythm token below still needs. */
    padding: var(--app-page-top) 0 var(--app-page-bottom) !important;
    min-height: 0 !important;
}

.app-shell .loader2 {
    /* Sized by the theme sheet that is no longer loaded; it is a spinner slot
       the JS toggles, so it must not reserve space while idle. */
    min-height: 0;
}

.app-shell .hidden {
    display: none !important;
}

/* Set on the Schedule column header and cell when the vendor hides the
   delivery schedule (settings.hide_delivery_schedule). */
.app-shell .hide_schedules {
    display: none !important;
}

.app-shell .remove_schedule_msg {
    display: block;
    width: 100%;
    margin-top: 4px;
    color: var(--cart-danger);
    font-size: 11.5px;
    font-weight: 500;
    text-align: right;
}

.app-shell button.disabled,
.app-shell .site-btn.disabled {
    opacity: .4;
    cursor: not-allowed;
    pointer-events: none;
}

/* --- Section headings ---------------------------------------------------- */

.app-shell .cart-section-title {
    margin: 0 0 10px;
    font-size: 12px;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--app-muted);
}


.app-shell .progress-bar-cart-wrap {
    margin: 0 0 18px !important;
    padding: 18px 0 4px;
}

.app-shell .progress-bar-steps {
    position: relative;
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
}

.app-shell .progress-bar-steps .step {
    position: relative;
    flex: 1 1 0;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    /* Above the connector drawn by the ::before below. */
    z-index: 1;
}

.app-shell .progress-bar-steps .step::before {
    content: "";
    position: absolute;
    top: 13px;
    right: calc(50% + 17px);
    left: calc(-50% - 16px + 17px);
    height: 2px;
    background: var(--cart-line);
    z-index: -1;
}

.app-shell .progress-bar-steps .step:first-child::before {
    display: none;
}

.app-shell .progress-bar-steps .step.active ~ .step::before {
    background: var(--cart-line);
}

.app-shell .progress-bar-steps .step .circle {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 26px !important;
    height: 26px !important;
    border-radius: 50%;
    border: 2px solid var(--cart-line);
    background: var(--cart-surface);
    color: var(--app-muted);
    font-size: 12px;
    font-weight: 700;
    line-height: 1;
    transition: background .18s ease, border-color .18s ease, color .18s ease;
}

.app-shell .progress-bar-steps .step .label {
    margin-top: 8px !important;
    font-size: 10.5px;
    font-weight: 600;
    line-height: 1.35;
    color: var(--app-muted);
    overflow-wrap: anywhere;
}

.app-shell .progress-bar-steps .step.active .circle,
.app-shell .progress-bar-steps .step.completed .circle {
    border-color: var(--app-theme);
    background: var(--app-theme);
    color: #fff;
}

.app-shell .progress-bar-steps .step.active .label,
.app-shell .progress-bar-steps .step.completed .label {
    color: var(--app-ink);
}

.app-shell .progress-bar-steps .step.completed + .step::before,
.app-shell .progress-bar-steps .step.active::before {
    background: var(--app-theme);
}


.app-shell .cart-top-30px .d-flex:has(> .box-radio) {
    gap: 8px;
    margin: 0 0 16px !important;
}

.app-shell .box-radio {
    margin: 0 !important;
    padding: 0;
}

.app-shell .box-radio .form-check-label {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    margin: 0;
    padding: 9px 14px;
    border: 1px solid var(--cart-line);
    border-radius: 999px;
    background: var(--cart-surface);
    font-size: 13px;
    font-weight: 600;
    color: var(--app-ink);
    cursor: pointer;
    transition: border-color .15s ease, background .15s ease, color .15s ease;
}

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

/* :has() keeps the checked styling on the label without asking the template
   for a JS-toggled class. */
.app-shell .box-radio .form-check-label:has(.form-check-input:checked) {
    border-color: var(--app-theme);
    background: var(--app-theme-soft);
}

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

/* On a phone the three chips wrap; .mobileFull must not force a full row. */
.app-shell .box-radio.mobileFull {
    width: auto;
}

/* --- Cards --------------------------------------------------------------
   One treatment, used by the picker panel, each cart line and the summary. */

.app-shell .flex-for-desktop,
.app-shell .cart-page-table .table_row,
.app-shell .order-detail-right,
.app-shell .righ-side-bar .panel-group,
.app-shell .cart-instructions {
    border: 1px solid var(--cart-line);
    border-radius: var(--cart-radius);
    background: var(--cart-surface);
    box-shadow: var(--cart-shadow);
}

/* --- Address / date / schedule panel ------------------------------------- */

.app-shell .flex-for-desktop {
    margin: 0 0 16px !important;
    padding: 16px;
    /* Overrides base.css's negative row gutters: this row is a padded card, so
       its children must not hang outside the padding. */
    margin-inline: 0 !important;
}

.app-shell .flex-for-desktop > [class*="col-"] {
    flex: 0 0 100%;
    max-width: 100%;
    padding-inline: 0;
}


@media (min-width: 768px) {
    .app-shell .flex-for-desktop {
        display: flex;
        flex-wrap: wrap;
        column-gap: 16px;
    }

    .app-shell .flex-for-desktop > [class*="col-"] {
        /* calc() so the two halves account for the gap between them. */
        flex: 0 0 calc(50% - 8px);
        max-width: calc(50% - 8px);
    }
    .app-shell .flex-for-desktop > [class*="col-"]:nth-last-child(2):first-child .shoping__cart__table,
    .app-shell .flex-for-desktop > [class*="col-"]:nth-last-child(2):first-child > label + input {
        margin-bottom: 0 !important;
    }
}

.app-shell .flex-for-desktop .shoping__cart__table {
    margin-bottom: 14px !important;
    /* visible so a native select's dropdown is not clipped by the card. */
    overflow: visible !important;
}

.app-shell .flex-for-desktop > [class*="col-"]:last-child .shoping__cart__table,
.app-shell .flex-for-desktop > [class*="col-"]:last-child > label + input {
    margin-bottom: 0 !important;
}

/* Field labels. .f-heavy is the template's own bold class. */
.app-shell .flex-for-desktop label.f-heavy,
.app-shell .righ-side-bar label.f-heavy,
.app-shell .cart-instructions label.f-heavy {
    display: block;
    margin-bottom: 6px !important;
    font-size: 11.5px;
    font-weight: 700;
    letter-spacing: .03em;
    text-transform: uppercase;
    color: var(--app-muted);
}

@media (min-width: 768px) {
    .app-shell .flex-for-desktop > [class*="col-"] > label.f-heavy,
    .app-shell .flex-for-desktop .shoping__cart__table > .d-flex {
        display: flex;
        align-items: center;
        min-height: 22px;
        margin-bottom: 6px !important;
    }

    /* The link must not inflate the row it shares with the label. */
    .app-shell .flex-for-desktop .shoping__cart__table > .d-flex label {
        margin-bottom: 0 !important;
    }
}

.app-shell .add_new_address {
    margin-bottom: 6px !important;
    margin-left: auto !important;
}

.app-shell .add_new_address_link,
.app-shell .add_new_address a {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    color: var(--app-theme);
    font-size: 12.5px;
    font-weight: 600;
    text-decoration: none;
}

.app-shell .add_new_address_link:hover {
    text-decoration: underline;
}

/* --- Form controls ------------------------------------------------------- */

.app-shell .cart-container select.form-control,
.app-shell .cart-container input.form-control,
.app-shell .cart-container textarea.form-control,
.app-shell .address_drop_down,
.app-shell .custom-cart-drop,
.app-shell .custom-cart-drop-pickup,
.app-shell #datepicker {
    width: 100%;
    min-height: 44px;
    padding: 10px 12px;
    border: 1px solid var(--cart-line);
    border-radius: var(--cart-radius-sm);
    background: var(--cart-surface);
    font-family: inherit;
    font-size: 13.5px;
    color: var(--app-ink);
    /* 44px min touch target; appearance reset so the control matches across
       iOS Safari and desktop Chrome. */
    -webkit-appearance: none;
    appearance: none;
    transition: border-color .15s ease, box-shadow .15s ease;
}

.app-shell .custom-cart-drop-pickup {
    display: none;
}

.app-shell .cart-container select.form-control,
.app-shell .address_drop_down,
.app-shell .custom-cart-drop,
.app-shell .custom-cart-drop-pickup {
    /* Room for the chevron drawn below. */
    padding-right: 34px;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%236b7280' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 12px center;
}

.app-shell .cart-container .form-control:focus,
.app-shell .address_drop_down:focus,
.app-shell #datepicker:focus {
    outline: none;
    border-color: var(--app-theme);
    box-shadow: 0 0 0 3px var(--app-theme-soft);
}

.app-shell .cart-container textarea.form-control {
    min-height: 84px;
    resize: vertical;
}

/* A disabled datepicker still reads as a field, not as dead text. */
.app-shell #datepicker[disabled] {
    background-color: #fafafb;
    color: var(--app-muted);
    cursor: not-allowed;
}

/* --- Clear cart ---------------------------------------------------------- */

.app-shell .cart-actions-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin: 0 0 var(--cart-head-gap);
    min-height: var(--cart-head-height);
}

.app-shell .cart-actions-row .under-line-txt {
    padding-right: 0;
}

/* The heading's own 10px bottom margin is for when it stands alone; inside the
   row it pushed the text up off the button's centre line. */
.app-shell .cart-actions-row .cart-section-title {
    margin: 0;
}

/* Minimal: a plain text action, not a filled pill. Clearing the cart is a
   destructive but rarely-wanted action sitting directly above the item list —
   as a tinted bordered button it pulled more attention than the items it would
   delete. Colour alone carries the warning; the tint only appears on hover. */
.app-shell .under-line-txt {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 8px;
    border: 0;
    border-radius: var(--cart-radius-sm);
    background: transparent;
    color: var(--cart-danger);
    font-family: inherit;
    font-size: 12.5px;
    font-weight: 600;
    text-decoration: none;
    cursor: pointer;
    transition: background .15s ease, opacity .15s ease;
}



/* The trash glyph does the signalling, so it can sit lighter than the word. */
.app-shell .under-line-txt i {
    font-size: 12px;
    opacity: .85;
}

/* --- Two-column split ---------------------------------------------------
   Items left, summary right, from 900px up. Below that they stack, items
   first — the summary is the thing you read last before paying. */

.app-shell .wrap-empty-case {
    margin-inline: 0 !important;
    row-gap: 0;
}

.app-shell .wrap-empty-case > [class*="col-"] {
    padding-inline: 0;
}
@media (max-width: 899.98px) {
    .app-shell .righ-side-bar {
        margin-top: var(--cart-gap);
    }
}

@media (min-width: 900px) {
    /* :not() so the two-column split does not apply to the empty page, which
       has no summary column and whose wrapper is a growing flex COLUMN (see
       the empty-state block below). Without this the row's flex-direction and
       align-items:flex-start would fight that. */
    .app-shell .wrap-empty-case:not(:has(.empty-responsive-wrap)) {
        display: flex;
        flex-wrap: nowrap;
        align-items: flex-start;
        gap: var(--cart-split-gap);
    }

    .app-shell .with-customize-wrap {
        flex: 1 1 auto;
        min-width: 0;
        max-width: none;
    }

    .app-shell .righ-side-bar {
        flex: 0 0 var(--cart-aside-width);
        max-width: var(--cart-aside-width);
        /* Matches the ITEMS / Clear Cart row that sits at the top of the items
           column, so the coupon card here and the first item card beside it
           start on the same line. The row is inside that column (it labels the
           list, and outside it it spanned both columns), so this side has to
           reserve the equivalent space rather than share the row itself.
           Only inside this query: below 900px the columns stack and the items
           column's own heading already sits above everything. */
        padding-top: calc(var(--cart-head-height) + var(--cart-head-gap));
    }
}

/* --- Item list ----------------------------------------------------------
   The markup is a pseudo-table: a .theader of column names, then one
   .table_row per item whose cells each carry their own label. Rebuilt as a
   stack of cards, which is what makes the same markup work at every width —
   the labels the desktop view hides are exactly what a narrow card needs. */

.app-shell .shoping__cart__table {
    overflow: visible !important;
    margin-bottom: 0;
}

/* .border-shadow is the desktop card frame; the cards inside carry their own. */
.app-shell .shoping__cart__table.border-shadow {
    border: 0;
    box-shadow: none;
    background: transparent;
    padding: 0;
}

.app-shell .cart-page-table .theader {
    display: none;
}

.app-shell .cart-page-table .table_row {
    display: block;
    position: relative;
    margin: 0 0 12px !important;
    padding: 14px;
    transition: border-color .15s ease, box-shadow .15s ease;
}

.app-shell .cart-page-table .table_row:hover {
    border-color: #e0e3e8;
    box-shadow: var(--cart-shadow-lift);
}

.app-shell .cart-page-table .table_row:last-child {
    margin-bottom: 0 !important;
}

/* Each cell becomes a label/value row. .w-20 and friends are desktop column
   widths and must not apply here. */
.app-shell .cart-page-table .table_small {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    width: 100% !important;
    max-width: none !important;
    padding: 7px 0;
    border: 0;
}

.app-shell .cart-page-table .table_cell:first-child {
    display: block;
    flex: 0 0 auto;
    font-size: 12px;
    font-weight: 600;
    color: var(--app-muted);
}

.app-shell .cart-page-table .table_cell:last-child {
    flex: 1 1 auto;
    min-width: 0;
    text-align: right;
    font-size: 13.5px;
    font-weight: 600;
    color: var(--app-ink);
}

/* Product header row: image + name, full width, ruled off from the fields.
   Right padding leaves room for the remove button pinned in the corner. */
.app-shell .cart-page-table .table_small:first-child {
    display: block;
    padding: 0 44px 12px 0;
    margin-bottom: 6px;
    border-bottom: 1px solid var(--cart-line-soft);
}

.app-shell .cart-page-table .table_small:first-child .table_cell:first-child {
    display: none;
}

.app-shell .cart-page-table .table_small:first-child .table_cell:last-child {
    text-align: left;
}

.app-shell .product-img-wrap {
    display: flex;
    align-items: center;
    gap: 12px;
}

.app-shell .pd-cart-img {
    flex: 0 0 60px;
    width: 60px;
    height: 60px;
    padding: 4px;
    border: 1px solid var(--cart-line);
    border-radius: 12px;
    background: #fafafb;
    object-fit: contain;
}

.app-shell .name-error-wrap {
    min-width: 0;
}

.app-shell .product-img-wrap a {
    color: var(--app-ink);
    text-decoration: none;
}

.app-shell .name-error-wrap h5 {
    margin: 0;
    font-size: 14px;
    font-weight: 600;
    line-height: 1.35;
    color: var(--app-ink);
}

.app-shell .name-error-wrap h5:hover {
    color: var(--app-theme);
}

.app-shell .procart.brandName {
    display: block;
    margin-bottom: 2px;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: .03em;
    text-transform: uppercase;
    color: var(--app-muted);
}

/* Unit / variant line under the name. */
.app-shell .name-error-wrap .procart:not(.brandName) {
    display: block;
    margin-top: 2px;
    font-size: 12px;
    color: var(--app-muted);
}

/* Per-item validation messages the JS writes into the name cell. */
.app-shell .name-error-wrap .error,
.app-shell .cart-page-table .error {
    display: block;
    margin-top: 4px;
    font-size: 11.5px;
    font-weight: 500;
    line-height: 1.4;
    color: var(--cart-danger);
}

/* Status badges on an item: out-of-stock / not-deliverable / age-restricted.
   These were defined only in the desktop cart.css, which this page does not
   load, so they are restated here. */
.app-shell .modern-unavailable-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    width: fit-content;
    margin-top: 4px;
    padding: 3px 8px;
    border: 1px solid var(--cart-danger-line);
    border-radius: 6px;
    background: var(--cart-danger-soft);
    color: #842029;
    font-size: 11px;
    font-weight: 600;
    /* The badge is a label, not a control — it must not swallow the click that
       reaches the product link behind it. */
    pointer-events: none;
}

.app-shell .age-restricted-badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-top: 4px;
    padding: 3px 10px;
    border: 1px solid #fed7aa;
    border-radius: 8px;
    background: #fff7ed;
    color: #b45309;
    font-size: 11.5px;
    font-weight: 600;
}

.app-shell .age-restricted-badge i,
.app-shell .modern-unavailable-badge i {
    font-size: 11px;
}

/* An unavailable item stays legible — it has to be removable. */
.app-shell .cart-page-table .table_row.unav {
    border-color: var(--cart-danger-line);
    background: #fffbfb;
}

/* The unavailable item's unit label reads as struck through. */
.app-shell .cart-page-table .table_row.unav span.f-heavy.text-capitalize {
    text-decoration: line-through;
}

.app-shell .cart-page-table .table_row.unav .table_small:not(:first-child) {
    opacity: .6;
}

/* The per-item total is the figure that matters, so it is ruled off from the
   price/tax lines and set heavier. Matched by position: it is the row
   immediately before the row holding the remove button. */
.app-shell .cart-page-table .table_small:has(+ .table_small .delete_item) {
    margin-top: 4px;
    padding-top: 10px;
    border-top: 1px solid var(--cart-line-soft);
}

.app-shell .cart-page-table .table_small:has(+ .table_small .delete_item) .table_cell:last-child {
    font-size: 16px;
    font-weight: 800;
}

/* The remove control: its "Action" label is redundant beside a bin icon, and
   it belongs with the product it removes, so it is lifted into the card's
   corner. Matched by the button it contains rather than :last-child, which
   would move the wrong field if the cell order ever changed. */
.app-shell .cart-page-table .table_small:has(.delete_item) {
    position: absolute;
    top: 12px;
    right: 12px;
    width: auto !important;
    padding: 0;
}

.app-shell .cart-page-table .table_small:has(.delete_item) .table_cell:first-child {
    display: none;
}

.app-shell .delete_item {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border-radius: 9px;
    background: var(--cart-danger-soft);
    color: var(--cart-danger);
    font-size: 13px;
    cursor: pointer;
    transition: background .15s ease;
}

.app-shell .delete_item:hover {
    background: #fee2e2;
}

/* --- Quantity stepper ---------------------------------------------------
   div.pro-qty, not bare .pro-qty: the schedule <select> shares that class. */

.app-shell .cart-page-table div.pro-qty,
.app-shell .cart-page-table .quantity {
    display: inline-flex !important;
    align-items: center;
    width: auto !important;
    margin: 0 0 0 auto !important;
    padding: 0;
}

.app-shell .cart-page-table div.pro-qty {
    height: 38px;
    border: 1px solid var(--cart-line);
    border-radius: var(--cart-radius-sm);
    overflow: hidden;
    background: var(--cart-surface);
}

.app-shell .cart-page-table .qtybtn {
    position: relative;
    display: block;
    flex: 0 0 36px;
    width: 36px;
    min-width: 36px;
    height: 100%;
    border: 0;
    background: #f7f8fa;
    /* The markup puts a literal "-" / "+" in the span; drawn as shapes below
       so both signs have identical weight and optical centring. */
    font-size: 0;
    color: transparent;
    cursor: pointer;
    user-select: none;
    transition: background .15s ease;
}

.app-shell .cart-page-table .qtybtn:hover {
    background: #eef0f3;
}

.app-shell .cart-page-table .qtybtn::before {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 11px;
    height: 2px;
    border-radius: 2px;
    background: var(--app-ink);
}

.app-shell .cart-page-table .qtybtn.inc::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 2px;
    height: 11px;
    border-radius: 2px;
    background: var(--app-ink);
}

.app-shell .cart-page-table div.pro-qty input,
.app-shell .cart-page-table .number-ip {
    width: 44px;
    height: 100%;
    padding: 0;
    border: 0;
    outline: 0;
    background: transparent;
    text-align: center;
    font-family: inherit;
    font-size: 14px;
    font-weight: 700;
    color: var(--app-ink);
    /* A disabled input greys out on iOS; the value must stay readable. */
    -webkit-text-fill-color: var(--app-ink);
    opacity: 1;
    -moz-appearance: textfield;
}

.app-shell .cart-page-table .number-ip::-webkit-outer-spin-button,
.app-shell .cart-page-table .number-ip::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

/* --- Per-item schedule / delivery-date selects --------------------------- */

.app-shell .cart-page-table select.pro-qty,
.app-shell .cart-page-table .schedule_drop_down,
.app-shell .cart-page-table .custom-cart-drop1,
.app-shell .cart-page-table .deliverydate {
    display: block;
    width: 100% !important;
    max-width: 220px;
    min-height: 40px;
    margin-left: auto;
    padding: 8px 32px 8px 10px;
    border: 1px solid var(--cart-line);
    border-radius: var(--cart-radius-sm);
    background-color: var(--cart-surface);
    font-family: inherit;
    font-size: 12.5px;
    color: var(--app-ink);
    /* Every other value in the row is right-aligned, but a select's own text
       reads better from the left — so only the control is pushed right. */
    text-align: left;
}

.app-shell .cart-page-table .hide_schedules {
    display: none !important;
}

/* --- Summary column ------------------------------------------------------ */

.app-shell .righ-side-bar > div {
    display: flex;
    flex-direction: column;
    gap: var(--cart-gap);
}

/* Driver-instruction accordion. */
.app-shell .righ-side-bar .panel-group {
    margin: 0 !important;
    padding: 4px 14px;
}

/* The same accordion in its own position at the foot of the items column. The
   top margin is the gap from the last cart line; the card treatment itself
   comes from the shared rule above. */
.app-shell .cart-instructions {
    margin: var(--cart-gap) 0 0 !important;
    padding: 4px 14px;
}

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

/* A static section label, not a control: default cursor and no hover colour,
   matching the chevron's removal above. */
.app-shell .instructionBtn {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 12px 0;
    color: var(--app-ink);
    font-size: 13.5px;
    font-weight: 600;
    text-decoration: none;
    cursor: default;
}

/* No collapse chevron. The panel renders `collapse in` and there is nothing
   below it in this column to reveal by folding it away, so the indicator only
   suggested an interaction that gains the customer nothing — the header now
   reads as a plain section label. */

.app-shell .ins-reason-section {
    max-width: 100%;
    padding: 0;
    border-radius: 8px;
    background: transparent;
    text-align: left;
}

.app-shell textarea.other-instruction {
    resize: vertical;
    font-size: 13.5px;
}

.app-shell .instruction-accordion .panel-body {
    padding: 0 0 14px;
}

.app-shell .instruction-accordion .panel-collapse:not(.in) {
    display: none;
}

/* The summary card. */
.app-shell .order-detail-right {
    display: block;
    width: 100%;
    margin: 0;
    padding: 16px;
}

/* .shipping_charge is a <label>; it must not inherit inline-block sizing. */
.app-shell .shipping_charge {
    display: block;
    width: 100%;
    margin: 0;
    font-weight: 400;
}

.app-shell .shipping_charge.float-right {
    float: none !important;
    text-align: left !important;
}

/* Each itemised line: label on the left, figure on the right.
   Laid out WITHOUT flex on the row itself. The JS show()/hide()s several of
   these (.deliveryCharges, .grandTotal, .grandTotalPickup), and jQuery's
   show() writes an inline `display: block` that would beat a stylesheet
   `display: flex` and collapse the row. Floating the <p> label and letting the
   figure sit in the remaining inline flow gives the same result under block,
   flow-root or flex, so the layout survives whatever jQuery last set. */
.app-shell .order-total,
.app-shell .sub-total-wrapper,
.app-shell .grandTotalTax,
.app-shell .couponDiscount,
.app-shell .containerCharge,
.app-shell .deliveryCharges,
.app-shell .d-flex-align {
    padding: 7px 0;
    font-size: 13.5px;
    font-weight: 600;
    text-align: right;
    color: var(--app-ink);
    /* Contains the floated label so the row keeps its own height. */
    overflow: hidden;
}

.app-shell .order-total p,
.app-shell .grandTotalTax p,
.app-shell .couponDiscount p,
.app-shell .containerCharge p,
.app-shell .deliveryCharges p,
.app-shell .d-flex-align p {
    float: left;
    max-width: 62%;
    margin: 0;
    font-weight: 500;
    text-align: left;
    color: var(--app-muted);
}

/* elm_container_summary's JS rewrites .containerCharge as
   `<div class="container-text-cart-heading"><b>Label:</b> <eye btn> <span>$0.00</span></div>`
   — no <p>, so the rule above did not reach it and that row alone sat with its
   label, icon and figure running together. Float the label group left and push
   the amount right so it lines up with Item Total / Total Tax above it. */
/* width:100% is what actually makes this work. .containerCharge also carries
   `d-flex-align`, which elm_apply_coupon's inline <style> defines as
   `display:flex`, so this div is a flex ITEM of that row and shrank to its
   content width — leaving margin-left:auto on the amount below with no free
   space to push into, which is why the figure sat next to the eye icon rather
   than at the row's end. Filling the row restores the space. */
.app-shell .containerCharge .container-text-cart-heading,
.app-shell .container-text-cart-heading {
    display: flex;
    align-items: center;
    gap: 6px;
    flex: 1 1 auto;
    width: 100%;
}

.app-shell .container-text-cart-heading > b {
    font-weight: 500;
    color: var(--app-muted);
}

.app-shell .container-text-cart-heading .round-btn {
    flex: 0 0 auto;
}

.app-shell .container-text-cart {
    margin-left: auto;
    font-weight: 600;
    color: var(--app-ink);
}

.app-shell .couponDiscount,
.app-shell .couponDiscount p {
    color: var(--cart-success);
}

/* Grand total: the number the customer is deciding on, so it is set apart from
   the itemised lines and is the largest figure on the page.
   Float-based for the same reason as the rows above — the JS show()/hide()s
   both of these, so their display property is not ours to rely on. */
.app-shell .grandTotal,
.app-shell .grandTotalPickup {
    margin-top: 10px;
    padding-top: 14px;
    border-top: 1px solid var(--cart-line);
    font-size: 20px;
    font-weight: 800;
    text-align: right;
    color: var(--app-ink);
    overflow: hidden;
}

/* Both are <span>s, so the float layout above had no line box to push the
   figure across: the JS-written `<b>Grand Total: </b>₹802.00` printed as one
   run at the left edge. A flex row puts the label and figure at opposite ends
   whichever markup last wrote it (the floats are ignored inside flex).
   Safe against the JS: .show() on .grandTotal only clears the inline display,
   so this rule comes back. .grandTotalPickup is hidden by the stylesheet, so
   its .show() writes an inline `display: inline` instead — matched and
   overridden here; a later .hide() writes `none`, which no longer matches. */
.app-shell .grandTotal,
.app-shell .grandTotalPickup[style*="display: inline"] {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 12px;
}

.app-shell .grandTotalPickup[style*="display: inline"] {
    display: flex !important;
}

/* `b` as well as `p`: the JS rewrites these rows as
   `<b>Grand Total: </b>$240.00` (see the .grandTotal html() calls in
   cart_new.php) while the server renders `<p>Grand Total: </p>`. Styling only
   the <p> left the JS-written label inline, so it ran straight into the figure
   and printed as "Grand Total$240.00". Both selectors so the row survives
   whichever markup last wrote it. */
.app-shell .grandTotal p,
.app-shell .grandTotalPickup p,
.app-shell .grandTotal > b,
.app-shell .grandTotalPickup > b {
    display: block;
    float: left;
    max-width: 55%;
    margin: 0;
    font-size: 14px;
    font-weight: 700;
    /* Optically aligns the small label with the large figure's baseline. */
    line-height: 1.9;
    text-align: left;
    color: var(--app-ink);
}

/* The pickup variant of the grand total. The template renders it as a sibling
   of .grandTotal with both visible, and only the delivery-charge JS ever hides
   one — so until a delivery date is picked the summary showed TWO "Grand Total"
   rows with different figures. Hidden here so .grandTotal is the only one on
   first paint; the JS calls .show() on this when the order is a pickup, and an
   inline display from jQuery outranks this rule. */
.app-shell .grandTotalPickup {
    display: none;
}

/* Cancels the grand-total divider. The margin and padding above go with it:
   .grandTotal's 10px margin + 14px padding exist to set the row apart FROM that
   rule, so leaving them once the border is gone just opens ~24px of unexplained
   space between Container Charges and Grand Total. */
.app-shell .border-top-wrap {
    margin-top: 0;
    padding-top: 0;
    border: 0;
}

/* --- Delivery charge note + tooltip -------------------------------------- */

.app-shell .delivery_charge_note,
.app-shell .free-delivery-wrapper {
    margin: 0 0 12px !important;
    padding: 11px 13px;
    border: 1px solid var(--app-theme-border);
    border-radius: 12px;
    background: var(--app-theme-soft);
    font-size: 12.5px;
    line-height: 1.45;
    color: var(--app-ink);
}

.app-shell .delivery_charge_note > [class*="col-"] {
    padding: 0;
    margin: 0 !important;
}

.app-shell .delivery_charge_note p,
.app-shell .delivery_charge_note .alert {
    margin: 0;
    padding: 0;
    border: 0;
    background: transparent;
    font-size: 12.5px;
    color: inherit;
}

.app-shell .delivery-label,
.app-shell .delivery-info-icon {
    color: var(--app-theme);
}

.app-shell .green-free {
    color: var(--cart-success);
    font-weight: 700;
}

/* The delivery breakdown tooltip. Positioned relative to its wrapper so it
   cannot be clipped by the summary card. */
.app-shell .delivery-wrapper {
    position: relative;
}

.app-shell .delivery-tooltip {
    position: absolute;
    right: 0;
    bottom: calc(100% + 8px);
    z-index: 5;
    display: none;
    min-width: 210px;
    padding: 10px 12px;
    border-radius: 10px;
    background: #1f2937;
    color: #fff;
    font-size: 11.5px;
    font-weight: 500;
    line-height: 1.5;
    box-shadow: var(--cart-shadow-lift);
}

.app-shell .delivery-wrapper:hover .delivery-tooltip,
.app-shell .delivery-info-icon:focus + .delivery-tooltip {
    display: block;
}

.app-shell .delivery-tooltip .tooltip-title {
    margin-bottom: 6px;
    font-weight: 700;
}

.app-shell .delivery-tooltip .tooltip-row {
    display: flex;
    justify-content: space-between;
    gap: 14px;
    padding: 2px 0;
}

.app-shell .delivery-tooltip .tooltip-row.total {
    margin-top: 5px;
    padding-top: 5px;
    border-top: 1px solid rgba(255, 255, 255, .2);
    font-weight: 700;
}

.app-shell .delivery-tooltip .arrow {
    position: absolute;
    right: 14px;
    top: 100%;
    width: 0;
    height: 0;
    border: 6px solid transparent;
    border-top-color: #1f2937;
}

/* --- Coupon -------------------------------------------------------------- */

/* The JS both shows and hides this button ($('.coupon_btn').show() / .hide()).
   jQuery writes an inline `display: block` on show, which would beat a plain
   `display: flex` here and collapse the icon/label/chevron layout — but
   `!important` cannot be used to win that fight, because it would equally
   override the inline `display: none` that hide() writes, and the button would
   never hide. Styling the inline-block box's contents instead sidesteps the
   display property altogether: the inner .coupon-btn-main is the flex row. */
/* One surface, not two. A dashed border inset inside a tinted fill read as a
   box within a box; a solid hairline on a white ground matches the Delivery
   Instructions card above it, so the sidebar is a consistent stack of cards
   rather than one tinted outlier. */
.app-shell .coupon_btn {
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    width: 100%;
    /* No top margin. This used to clear the Delivery Instructions card that sat
       above it in this column; that card has since moved to the foot of the
       items column, leaving the coupon button as the column's FIRST child. The
       margin then stacked on top of the column's own head-row reservation and
       pushed this card ~14px below the item card it is supposed to line up
       with. !important because the template's own `mb-3` utility would
       otherwise set the bottom. */
    margin: 0 !important;
    padding: 14px;
    border: 1px solid var(--cart-line);
    border-radius: var(--cart-radius);
    background: var(--cart-surface);
    color: var(--app-theme);
    font-size: 13.5px;
    font-weight: 600;
    text-align: left;
    text-decoration: none;
    cursor: pointer;
    transition: border-color .15s ease, background .15s ease;
}

.app-shell .coupon_btn:hover {
    border-color: var(--app-theme);
    background: var(--app-theme-soft);
}

/* Carries the row layout so .coupon_btn's own display can stay whatever jQuery
   last set it to (see the note on .coupon_btn above). */
.app-shell .coupon-btn-main {
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
    width: 100%;
}

/* The label takes the slack so the chevron is pushed to the far edge. */
.app-shell .coupon-btn-main .coupon-title {
    flex: 1 1 auto;
}

.app-shell .coupon-btn-icon {
    flex: 0 0 22px;
    width: 22px;
    height: auto;
}

.app-shell .coupon-btn-chevron {
    flex: 0 0 auto;
    font-size: 11px;
    opacity: .7;
}

/* elm_apply_coupon.php carries an inline <style> giving .coupon-title a
   `2px dashed` border and its own padding — that is what drew the second, inner
   box inside this button. Cleared here: the button itself is the surface, the
   label is just text on it. */
.app-shell .coupon-title {
    margin: 0;
    padding: 0;
    border: 0;
    border-radius: 0;
    font-size: 13.5px;
    font-weight: 600;
    color: inherit;
}

.app-shell .select-coupon,
.app-shell .click-coupon {
    color: var(--app-theme);
    font-weight: 600;
    text-decoration: none;
    cursor: pointer;
}

.app-shell .coupon_discount {
    margin-bottom: 8px;
}

.app-shell .coupon-error {
    color: var(--cart-danger);
    font-size: 12.5px;
}

/* A small round counter/indicator the JS renders inside the container summary. */
/* The "view container summary" affordance on the Container Charges row. Styled
   as a quiet icon button rather than a solid filled badge: it sits beside the
   `?` on the Total Tax row directly above, and a filled theme-coloured dot read
   as a notification count next to a figure. Colour on hover only. */
/* .containerCharge in the selector: elm_container_summary.php's inline <style>
   sets `.containerCharge .round-btn { background: var(--default-color) }`, an
   equal-specificity rule that sits in the BODY and so wins on source order.
   Three classes outranks it without !important. */
.app-shell .containerCharge .round-btn,
.app-shell .round-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 18px;
    height: 18px;
    padding: 0 4px;
    /* The element also carries Bootstrap's .btn, whose border and focus shadow
       drew a theme-coloured ring round the eye, and whose 1.5 line-height sat
       the glyph above the label's centre. */
    border: 0;
    box-shadow: none;
    line-height: 1;
    border-radius: 999px;
    background: transparent;
    color: var(--app-muted);
    font-size: 11px;
    font-weight: 700;
    cursor: pointer;
    transition: color .15s ease;
}

.app-shell .containerCharge .round-btn:focus,
.app-shell .round-btn:focus {
    box-shadow: none;
}

.app-shell .containerCharge .round-btn:hover,
.app-shell .round-btn:hover {
    color: var(--app-theme);
}

.app-shell span.custom-text {
    color: var(--app-ink);
    font-weight: 600;
}

.app-shell .coupon-message {
    color: var(--cart-success);
    font-size: 12.5px;
}

/* --- Coupon picker (#couponModal, element/cart/elm_apply_coupon.php) --------
   The list is a <ul> that kept the browser's default 40px left padding, so
   every coupon card sat indented with a grey strip down its left; the rows
   themselves were flex lines of radio + code + message with fixed desktop
   offsets. Rebuilt as a stack of selectable cards: the code as a dashed
   "ticket" chip, the offer under it, the chosen card tinted with the theme.
   Keyed on the modal's id — this sheet is the layout 1 cart's only, and the
   element's inline <style> is unscoped, so an id is what reliably outranks it. */

#couponModal .modal-header {
    align-items: center;
    padding: 16px 18px;
}

#couponModal .modal-title {
    margin: 0;
    font-size: 15px;
    letter-spacing: .04em;
}

#couponModal .modal-body {
    padding: 14px 16px 16px;
    background: #f6f7f9;
}

#couponModal #myCouponSearch {
    width: 100%;
    min-height: 44px;
    padding: 10px 14px 10px 38px;
    border: 1px solid #dfe3e8;
    border-radius: 12px;
    background: #fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%239aa1ab' stroke-width='2.4' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='M20 20l-3.5-3.5'/%3E%3C/svg%3E") no-repeat 14px center;
    color: var(--app-ink);
    font-family: inherit;
    font-size: 14px;
    box-sizing: border-box;
}

#couponModal #myCouponSearch:focus {
    border-color: var(--app-theme);
    box-shadow: 0 0 0 3px var(--app-theme-soft);
    outline: 0;
}

#couponModal #myMenuCoupons {
    display: grid;
    gap: 10px;
    margin: 12px 0 0;
    padding: 0;
    list-style: none;
}

/* An empty <li> the template leaves in the list (a commented-out loop). */
#couponModal #myMenuCoupons > li:empty {
    display: none;
}

/* One card per coupon: radio in a narrow first column, code + offer beside it. */
#couponModal #myMenuCoupons li.coupon-li-tag {
    display: grid;
    grid-template-columns: 22px minmax(0, 1fr);
    column-gap: 10px;
    row-gap: 6px;
    align-items: center;
    margin: 0;
    padding: 14px;
    border: 1px solid #e4e6ea;
    border-radius: 14px;
    background: #fff;
    cursor: pointer;
    transition: border-color .15s ease, background .15s ease, box-shadow .15s ease;
}

#couponModal #myMenuCoupons li.coupon-li-tag:hover {
    border-color: var(--app-theme-border, var(--app-theme));
}

#couponModal #myMenuCoupons li.coupon-li-tag:has(.select-coupon:checked),
#couponModal #myMenuCoupons li.coupon-li-tag.coupon_success {
    border-color: var(--app-theme);
    background: var(--app-theme-soft);
    box-shadow: inset 0 0 0 1px var(--app-theme);
}

#couponModal .coupon-li-tag .form-check {
    grid-column: 1;
    grid-row: 1 / span 2;
    display: flex;
    align-items: center;
    justify-content: center;
    margin: 0;
    padding: 0;
}

#couponModal .coupon-li-tag .select-coupon {
    position: static;
    width: 18px;
    height: 18px;
    margin: 0;
    accent-color: var(--app-theme);
    cursor: pointer;
}

/* The code as a ticket chip. */
#couponModal .coupon-li-tag .coupon-title {
    grid-column: 2;
    justify-self: start;
    margin: 0;
    padding: 3px 10px;
    border: 1.5px dashed var(--app-theme);
    border-radius: 6px;
    background: #fff;
    color: var(--app-theme);
    font-size: 13px;
    font-weight: 800;
    letter-spacing: .04em;
    text-transform: uppercase;
}

#couponModal .coupon-li-tag .coupon-message {
    grid-column: 2;
    margin: 0;
    color: var(--cart-success, #15803d);
    font-size: 13px;
    line-height: 1.45;
}

#couponModal .coupon-li-tag .coupon-error:not(:empty) {
    grid-column: 2;
    color: var(--cart-danger, #dc2626);
    font-size: 12px;
}

#couponModal #emptyCouponList {
    margin: 20px 0 8px;
    padding: 12px;
}

/* Footer: the savings figure left, Apply right. */
#couponModal .modal-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
    padding: 12px 16px;
}

#couponModal .coupon_saving {
    font-size: 12.5px;
    line-height: 1.35;
    color: var(--app-muted);
}

#couponModal .coupon_saving b {
    color: var(--app-ink);
    font-size: 15px;
}

#couponModal .apply_coupon_btn {
    min-width: 130px;
    min-height: 46px;
    margin: 0 0 0 auto;
    padding: 0 26px;
    border: 0;
    border-radius: 12px;
    background: var(--app-theme);
    color: #fff;
    font-family: inherit;
    font-size: 15px;
    font-weight: 700;
}

#couponModal .apply_coupon_btn:disabled {
    opacity: .5;
    cursor: not-allowed;
}

/* --- Payment methods ----------------------------------------------------- */

/* Its own card, matching .order-detail-right above it. Previously this block
   had no surface of its own, so the payment radios sat flush against the
   summary's bottom edge and the two read as one box that had broken open —
   "Select Payment Method" appeared to be inside the totals panel. */
.app-shell .payment-method-container {
    margin: 12px 0 0 !important;
    padding: 16px;
    border: 1px solid var(--cart-line);
    border-radius: var(--cart-radius);
    background: var(--cart-surface);
    box-shadow: var(--cart-shadow);
}

.app-shell .payment-method-container > [class*="col-"] {
    padding: 0;
}

.app-shell .select-pay-label {
    display: block;
    margin-bottom: 10px !important;
    font-size: 12px !important;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--app-muted);
}

/* Payment options reuse the .box-radio markup of the delivery chips, but here
   they are full-width selectable rows: their labels carry a gateway name and
   sometimes a balance, so a pill would truncate them. */
.app-shell .payment-method-container .box-radio,
.app-shell .righ-side-bar .box-radio {
    display: block;
    width: 100%;
    margin-bottom: 8px !important;
}

.app-shell .payment-method-container .box-radio .form-check-label,
.app-shell .righ-side-bar .box-radio .form-check-label {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    min-height: 56px;
    padding: 10px 14px;
    border-color: #e3e5e9;
    border-radius: 12px;
    font-size: 14px;
    line-height: 1.35;
}

/* Same card as the product page's subscription payment list
   (v1/product_detail.css): logo, name, (wallet balance), then the radio at the
   right edge. Explicit `order` puts the radio last whatever the source order;
   its auto margin pushes it right, or the balance takes the auto margin when
   present and the radio follows at the normal gap. */
.app-shell .payment-method-container .box-radio label img,
.app-shell .righ-side-bar .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;
}

.app-shell .payment-method-container .box-radio .update_wallet,
.app-shell .righ-side-bar .box-radio .update_wallet {
    order: 2;
}

.app-shell .payment-method-container .box-radio .form-check-input,
.app-shell .righ-side-bar .box-radio .form-check-input {
    order: 3;
    flex: 0 0 18px;
    width: 18px;
    height: 18px;
    margin: 0 0 0 auto;
}

.app-shell .payment-method-container .box-radio label:has(.update_wallet) .form-check-input,
.app-shell .righ-side-bar .box-radio label:has(.update_wallet) .form-check-input {
    margin-left: 0;
}

.app-shell .update_wallet {
    margin-left: auto;
    font-weight: 700;
    color: var(--app-theme);
}

/* --- Receipt upload ------------------------------------------------------ */

.app-shell .upload-receipt-wrap {
    padding: 14px;
    border: 1px dashed var(--cart-line);
    border-radius: 12px;
    background: #fafafb;
}

.app-shell .upload-receipt.custom-file {
    position: relative;
    display: block;
    width: 100%;
    height: auto;
    margin-bottom: 8px;
}

.app-shell .upload-receipt .custom-file-input {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    opacity: 0;
    cursor: pointer;
}

.app-shell .upload-receipt .custom-file-label {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    min-height: 44px;
    margin: 0;
    padding: 10px 14px;
    border: 1px solid var(--cart-line);
    border-radius: var(--cart-radius-sm);
    background: var(--cart-surface);
    font-size: 13px;
    font-weight: 600;
    color: var(--app-ink);
    cursor: pointer;
}

.app-shell .showBankDetails {
    display: inline-block;
    margin-bottom: 8px;
    color: var(--app-theme);
    font-size: 12.5px;
    font-weight: 600;
    text-decoration: none;
    cursor: pointer;
}

.app-shell #filePreview img {
    max-width: 100%;
    height: auto;
    border-radius: var(--cart-radius-sm);
}

.app-shell .errorReceipt {
    display: block;
    color: var(--cart-danger);
    font-size: 12px;
}

/* --- Alerts -------------------------------------------------------------- */

.app-shell .cart-container .alert {
    margin: 0;
    padding: 11px 13px;
    border-radius: 12px;
    border: 1px solid transparent;
    font-size: 12.5px;
    line-height: 1.45;
}

.app-shell .cart-container .alert-warning {
    border-color: #fde68a;
    background: #fffbeb;
    color: #92400e;
}

/* Matched to .app-notice, the amber announcement banner on the home page
   (app-mobile.css) — same gradient, hairline, 4px accent bar and warm brown
   ink, so an informational note reads the same wherever it appears in the app.
   The values are restated rather than the class reused: .app-notice carries the
   home page's own margins and lives outside this sidebar. */
/* The wrapper is a Bootstrap .row inside a .col — both of which carry gutters
   and, from base.css, negative side margins. Flattened to nothing so the amber
   note below is the only thing that paints: with the wrapper still contributing
   padding and the note carrying a shadow, the pair read as a grey panel with a
   second box floating inside it. */
.app-shell .delivery_charge_note {
    margin: 0 !important;
    padding: 0 !important;
    border: 0 !important;
    background: none !important;
    box-shadow: none !important;
}

.app-shell .delivery_charge_note > [class*="col-"] {
    margin: 0 !important;
    padding: 0 !important;
    border: 0 !important;
    background: none !important;
    box-shadow: none !important;
}

/* .cart-container in the selector as well: the generic amber rule above is
   `.app-shell .cart-container .alert-warning`, an equal-specificity tie that
   source order alone would settle. Stated explicitly so this keeps winning if
   either rule moves. */
.app-shell .cart-container .delivery_charge_note .alert-warning {
    margin: 0;
    padding: 12px 14px;
    border: 1px solid #f2d999;
    border-left: 4px solid #e0a020;
    border-radius: 10px;
    background: linear-gradient(180deg, #fff9e8, #fff4d6);
    color: #6b4c12;
    font-size: 13px;
    font-weight: 500;
    line-height: 1.45;
    /* No shadow: .app-notice has one because it sits on the page's grey
       backdrop, but here it sits in a white sidebar where the lift only made
       the note look like it was floating on a second surface. */
    box-shadow: none;
}

/* "Delivery Charges:" heading inside the note. Darker than the body copy but
   still within the amber family, as in .app-notice. */
.app-shell .delivery_charge_note .alert-warning b {
    color: #5a3f0d;
    font-weight: 700;
}

.app-shell .cart-container .alert-danger {
    border-color: var(--cart-danger-line);
    background: var(--cart-danger-soft);
    color: #991b1b;
}

.app-shell .credit_limit_error,
.app-shell .sage_note {
    margin: 0 !important;
}

/* Card-verification note (TMC61) — the same cream notice as the Delivery
   Charges box above it, rather than loose muted text between the totals card
   and Add Credit Card. */
.app-shell .cart-container .sage_note,
.app-shell p.sage_note {
    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 .cart-container .sage_note b,
.app-shell p.sage_note b {
    font-weight: 700;
    color: #6b4c12;
}

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

/* Owns the spacing around Place Order and the gateway buttons. A flex column
   with a gap rather than margins on the children: on auto-debit gateways
   .place_order is hidden until a card is linked, and a `display: none` child
   contributes no gap — so the run of buttons closes up instead of leaving a
   hole where it would have been. */
.app-shell .cart-actions {
    display: flex;
    flex-direction: column;
    gap: 12px;
    margin-top: 12px;
}

/* Nothing inside is a gap-producing sibling when it is empty: the gateway row
   only renders buttons for the one active gateway, and the others collapse. */
.app-shell .cart-actions:empty {
    display: none;
}

/* No `display` is declared on .place_order: the JS show()/hide()s it, and a
   stylesheet display would be overwritten by jQuery's inline one anyway. A
   button is inline-block by default and these are full-width with centred
   text, so the result is identical without depending on the property.
   (.site-btn on an <a> needs the block-level behaviour spelled out, hence the
   separate rule below.) */
.app-shell .cart-container .site-btn,
.app-shell .place_order {
    gap: 8px;
    width: 100%;
    min-height: 50px;
    padding: 13px 22px;
    border: 0;
    border-radius: 12px;
    background: var(--app-theme);
    color: #fff;
    font-family: inherit;
    font-size: 15px;
    font-weight: 700;
    line-height: 1.2;
    text-align: center;
    text-decoration: none;
    cursor: pointer;
    transition: filter .15s ease, box-shadow .15s ease;
}

/* An <a class="site-btn"> is inline by default, so it needs the box behaviour
   stated. :not(.place_order) because that one button IS a JS show()/hide()
   target — see the note above; everything else here is static. */
.app-shell .cart-container a.site-btn:not(.place_order),
.app-shell .cart-container input.site-btn:not(.place_order),
.app-shell .cart-container button.site-btn:not(.place_order) {
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

/* Centres the label on a <button> whose display jQuery may have set to block. */
.app-shell .place_order {
    text-align: center;
}

.app-shell .cart-container .site-btn:hover,
.app-shell .place_order:hover {
    filter: brightness(.94);
    box-shadow: var(--cart-shadow-lift);
    color: #fff;
}

.app-shell .cart-container .site-btn:disabled,
.app-shell .place_order:disabled {
    opacity: .55;
    cursor: not-allowed;
    filter: none;
    box-shadow: none;
}

/* The gateway buttons sit in a row that must wrap rather than overflow. */
.app-shell .responsive-tablet-wrap {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin: 0 !important;
}

.app-shell .responsive-tablet-wrap > * {
    flex: 1 1 100%;
}

/* --- Empty state --------------------------------------------------------
   Centred in the space between the breadcrumb and the fixed nav, rather than
   floating at the top of a tall empty page. */

/* Centring the empty state needs the height to centre WITHIN.

   .app-shell is a flex column in which only .app-shell-spacer grows, so by
   default this block gets its natural height, the spacer swallows the rest,
   and the artwork sits high with dead space beneath it. A fixed min-height
   (50vh) does not fix that — it just centres inside an arbitrary box that is
   still the wrong size and still leaves a gap below.

   So the chain from the shell down to this element is made to grow instead:
   the container and section stretch to fill whatever the page leaves over, and
   the empty state centres inside the real remaining space. Scoped to
   :has(.empty-responsive-wrap) so a cart WITH items is untouched — there the
   container must keep its natural height and let the spacer do its job. */
.app-shell .cart-container:has(.empty-responsive-wrap) {
    display: flex;
    flex-direction: column;
    /* Grows in .app-shell's column, alongside .app-shell-spacer. */
    flex: 1 1 auto;
    min-height: 0;
}

.app-shell .cart-container:has(.empty-responsive-wrap) .cart-top-30px,
.app-shell .cart-container:has(.empty-responsive-wrap) .wrap-empty-case,
.app-shell .cart-container:has(.empty-responsive-wrap) .with-customize-wrap,
.app-shell .cart-container:has(.empty-responsive-wrap) .shoping__cart__table {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
}

/* .app-shell-spacer is the shell's own growing child. Left alone it splits the
   free space with the container above, so the empty state still centres in only
   part of the page and a gap remains beneath it — which is exactly what the
   fixed 50vh version looked like. Collapsing it on the empty cart hands the
   whole remainder to the container, so the artwork centres in the real space.
   Only on this page, and only when the cart is empty. */
.app-shell:has(.cart-container .empty-responsive-wrap) .app-shell-spacer {
    flex: 0 0 auto;
}

.app-shell .empty-responsive-wrap {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    /* Fills the height handed down by the chain above. The min-height is only a
       floor for the no-:has() fallback, where that chain does not apply. */
    flex: 1 1 auto;
    min-height: 46vh;
    padding: 28px var(--app-pad);
    text-align: center;
}

.app-shell .empty-img-wrap {
    width: 100%;
    max-width: 140px !important;
    height: auto;
    margin-bottom: 20px !important;
    padding: 20px;
    border-radius: 50%;
    background: var(--app-theme-soft);
    box-sizing: content-box;
}

/* Empty-cart mark: a plain cart icon on a soft theme disc, in place of the
   animated GIF that used to sit here. */
.app-shell .cart-empty-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 88px;
    height: 88px;
    margin-bottom: 20px;
    border-radius: 50%;
    background: var(--app-theme-soft);
    color: var(--app-theme);
    font-size: 36px;
}

.app-shell .empty-responsive-wrap h3 {
    margin: 0 0 18px;
    font-size: 17px;
    font-weight: 700;
    color: var(--app-ink);
}

.app-shell .empty-responsive-wrap .site-btn {
    width: auto;
    min-width: 200px;
}

/* Logged-out empty cart: a hint line, then a single Login button. */
.app-shell .empty-responsive-wrap .cart-empty-sub {
    margin: -10px 0 18px;
    color: var(--app-muted);
    font-size: 14px;
    line-height: 1.5;
}

.app-shell .empty-responsive-wrap .cart-empty-actions {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 10px;
    width: 100%;
    max-width: 260px;
}

.app-shell .empty-responsive-wrap .cart-empty-actions .site-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    width: 100%;
    min-width: 0;
}

/* --- Modals -------------------------------------------------------------
   Only Bootstrap's modal CSS is loaded by the layout, so the inner chrome is
   styled here to match the page. */

.app-shell ~ .modal .modal-content,
.modal .modal-content {
    border: 0;
    border-radius: var(--cart-radius);
    box-shadow: 0 20px 50px rgba(16, 24, 40, .18);
}

.modal .modal-header,
.modal .modal-footer {
    padding: 16px;
    border-color: #ecedf0;
}

.modal .modal-title {
    font-size: 15px;
    font-weight: 700;
}

.modal .modal-body {
    padding: 16px;
}

.modal .close {
    padding: 0;
    border: 0;
    background: transparent;
    font-size: 24px;
    line-height: 1;
    opacity: .5;
    cursor: pointer;
}

.modal .close:hover {
    opacity: 1;
}

/* --- Responsive ---------------------------------------------------------- */

@media (max-width: 575px) {
    .app-shell .progress-bar-steps .step .label {
        font-size: 9.5px;
    }

    .app-shell .cart-page-table .table_row {
        padding: 12px;
    }

    .app-shell .pd-cart-img {
        flex-basis: 52px;
        width: 52px;
        height: 52px;
    }

    /* Long value + long label stop fitting on one line well before this, so
       the schedule and date selects take a line of their own. */
    .app-shell .cart-page-table .table_small:has(select) {
        flex-direction: column;
        align-items: stretch;
        gap: 6px;
    }

    .app-shell .cart-page-table .table_small:has(select) .table_cell:last-child {
        text-align: left;
    }

    .app-shell .cart-page-table select.pro-qty,
    .app-shell .cart-page-table .schedule_drop_down,
    .app-shell .cart-page-table .custom-cart-drop1,
    .app-shell .cart-page-table .deliverydate {
        max-width: none;
        margin-left: 0;
    }

    /* The row stays a row on phones: "Items (n)" left, "Clear Cart" right.
       It used to stack into a column with the button centred on its own line,
       which detached the action from the list heading and cost a line. Both
       pieces are short enough to share the width at any phone size. */
    .app-shell .cart-actions-row .cart-section-title {
        min-width: 0;
    }

    .app-shell .cart-actions-row .under-line-txt {
        flex: 0 0 auto;
        white-space: nowrap;
    }
}

/* The chips scroll rather than wrap onto three rows on the narrowest phones. */
@media (max-width: 359px) {
    .app-shell .cart-top-30px .d-flex:has(> .box-radio) {
        flex-wrap: nowrap;
        overflow-x: auto;
        scrollbar-width: none;
    }

    .app-shell .cart-top-30px .d-flex:has(> .box-radio)::-webkit-scrollbar {
        display: none;
    }

    .app-shell .box-radio .form-check-label {
        white-space: nowrap;
    }
}

/* --- Fallback for browsers without :has() -------------------------------
   :has() carries the checked-chip styling, the corner remove button and the
   emphasised per-item total. Where it is unsupported the page must still be
   usable, so those elements fall back to their ordinary flow position. */

@supports not selector(:has(*)) {
    .app-shell .cart-page-table .table_small {
        position: static !important;
    }

    .app-shell .cart-page-table .table_small .table_cell:first-child {
        display: block;
    }

    .app-shell .cart-page-table .table_row {
        padding-top: 14px;
    }

    .app-shell .box-radio .form-check-input:checked + .form-check-label,
    .app-shell .box-radio .form-check-input:checked ~ .form-check-label {
        border-color: var(--app-theme);
        background: var(--app-theme-soft);
    }
}

/* --- Print --------------------------------------------------------------- */

@media print {
    .app-shell .under-line-txt,
    .app-shell .place_order,
    .app-shell .coupon_btn,
    .app-shell .payment-method-container,
    .app-shell .responsive-tablet-wrap {
        display: none !important;
    }
}
