/* ============================================================================
   Layout 1 — Cart, redesigned.

   Scoped under .app-shell throughout. The template carries inline <style>
   blocks in the body (gateway visibility toggles), which win ties against
   <head> CSS, so the extra .app-shell specificity here is what keeps these
   rules in charge.

   This sheet is self-contained: the page deliberately does not load the
   desktop cart.css, whose `.container { max-width: 90% !important }` is a
   percentage of the VIEWPORT rather than of the 1100px app frame, and which
   pulled the footer out to the browser edge.

   Colours come from the vendor's own settings via the tokens default1.php
   publishes (--app-theme, --app-theme-soft, --app-theme-border) plus the
   shell's own --app-ink / --app-muted / --app-pad. No brand colour is
   hard-coded. Neutrals and the single red used for destructive actions are
   literal, matching the rest of the v1 sheets.
   ========================================================================= */

.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;
}

/* --- Page frame ---------------------------------------------------------
   The shell already supplies the centred 1100px column and its side padding.
   The page's job is only to sit inside it without re-introducing a width. */

.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. */
    padding: 4px 0 24px !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;
}

/* --- Utilities the page's own JS depends on ------------------------------
   These were only ever declared in the desktop cart.css, which this page
   deliberately does not load. They are behavioural, not decorative: the JS
   toggles them expecting an effect, so they must be restated here.

   .hidden — added to the "Custom" delivery chip when a next-delivery schedule
   is forced, and used on a bootbox button. Without a display rule the JS still
   runs but the element it "hid" stays on screen. */
.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;
}

/* Inline "Please Select Another Delivery Date." warning, injected by the JS
   next to a schedule select and removed on the next recalculation. It is
   positioned out of the cell in the desktop grid; in the card layout it reads
   better as an ordinary block under the control, so it is NOT absolute here —
   absolute positioning against a card would overlap the row below. */
.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);
}

/* --- Progress steps ------------------------------------------------------
   Four labelled checkpoints. The connector is drawn on the track behind the
   circles rather than as a border on each step, so it cannot break between
   items when a label wraps to a different height. */

.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;
    /* Real separation between steps so a long label ("Address, Delivery date &
       Schedule date") stops short of the neighbouring circles instead of running
       under them. With gap:4px the four labels read as one run-on line. */
    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;
}

/* The connector: one segment per gap, anchored to the circle's vertical
   centre. Drawn from each step except the first, back toward the previous.
   The left edge reaches back across the 16px flex gap as well as the previous
   half step, then forward 17px to clear that circle: -50% - 16px + 17px. The
   right edge stops 17px short of this step's own circle (26px wide + 4px). */
.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);
    /* Long labels ("Address, Delivery date & Schedule date") must wrap inside
       their quarter rather than widening the track. */
    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);
}

/* --- Choice chips (delivery type) ---------------------------------------
   Custom / Add Next Delivery / Pickup. The template wraps each in
   .form-check.box-radio with the input inside the label. */

.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 {
    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;
}

/* Two per row once there is width for it: Delivery Address beside Delivery Date
   (and the optional Delivery Schedule column wrapping to the next line rather
   than squeezing all three). Stays stacked below this, where a half-width
   address select would truncate the street line.
   column-gap only — the row-gap would double up with the 14px bottom margin
   .shoping__cart__table already carries. */
@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);
    }

    /* The :last-child margin reset above assumes one column per row. With two,
       the left-hand column of the final pair sits on that same bottom row and
       should drop its margin too — but only when it IS the final pair, i.e.
       exactly two children. With three (the optional Schedule column) the
       second wraps onto row two and keeps its margin. */
    .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 {
    display: block;
    margin-bottom: 6px !important;
    font-size: 11.5px;
    font-weight: 700;
    letter-spacing: .03em;
    text-transform: uppercase;
    color: var(--app-muted);
}

/* The two columns caption their field differently: Delivery Address wraps its
   label in a .d-flex row alongside the "Add New Address" link (13px), while
   Delivery Date is a bare 11.5px label. That made the left caption taller, so
   the select sat lower than the date input beside it. Pinning both captions to
   one height lines the controls up on a shared baseline.
   Applied only at the two-column breakpoint — stacked, there is nothing to
   align to and the extra height would just be a gap. */
@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;
    }
}

/* Pushed to the right end of the label row. The markup uses Bootstrap's
   `ml-auto`, which v1/base.css does not reimplement, so without this the link
   sat immediately after the "Delivery Address" label instead of opposite it.
   margin-left:auto rather than redefining .ml-auto globally — this is the only
   place on the page that needs it. */
.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;
}

/* The pickup-location select. The template renders it empty next to the address
   dropdown and the JS only calls .hide() on it after DOM ready, so it painted as
   a second, blank address box under the real one. Hidden from the start; the JS
   .show()s it for pickup orders and that inline style outranks this. */
.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 10px;
}

/* 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;
}

.app-shell .under-line-txt:hover {
    background: var(--cart-danger-soft);
}

/* 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 (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: 20px;
    }

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

    .app-shell .righ-side-bar {
        flex: 0 0 336px;
        max-width: 336px;
    }
}

/* --- 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;
    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;
}

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

.app-shell .instructionBtn {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 12px 0;
    color: var(--app-ink);
    font-size: 13.5px;
    font-weight: 600;
    text-decoration: none;
    cursor: pointer;
}

.app-shell .instructionBtn:hover {
    color: var(--app-theme);
}

/* The open/closed indicator. Bootstrap's collapse plugin toggles .collapsed on
   the trigger, and the desktop sheet drew a +/- from it; a chevron that rotates
   is the same signal without the baseline-shifting glyph swap. */
.app-shell .instructionBtn::after {
    content: "\f077";
    font-family: "Font Awesome 6 Free";
    font-weight: 900;
    margin-left: auto;
    font-size: 11px;
    color: var(--app-muted);
    transition: transform .18s ease;
}

.app-shell .instructionBtn.collapsed::after {
    transform: rotate(180deg);
}

.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;
}

/* `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;
}

.app-shell .border-top-wrap {
    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%;
    /* Top margin, not 0: this button sits inside .right-side-content rather than
       the sidebar's flex wrapper, so the `gap: var(--cart-gap)` that spaces the
       other cards never reaches it and it sat flush against the Delivery
       Instructions card above. !important because the template's own `mb-3`
       utility would otherwise set the bottom. */
    margin: var(--cart-gap) 0 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;
    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: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;
}

/* --- 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;
    width: 100%;
    padding: 13px 14px;
    border-radius: 12px;
    font-size: 13.5px;
}

.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;
}

.app-shell .sage_note {
    font-size: 12.5px;
    color: var(--app-muted);
}

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

/* 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;
}

.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;
}

/* --- 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;
    }

    .app-shell .cart-actions-row {
        flex-direction: column;
        align-items: stretch;
    }

    .app-shell .under-line-txt {
        justify-content: center;
    }
}

/* 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;
    }
}
