/**
 * COD form — the shared field + CTA component.
 *
 * Single source of truth for the cash-on-delivery form's look. Two consumers:
 *
 *   inc/woocommerce/checkout/       single-product Quick Checkout  (the master)
 *   inc/woocommerce/checkout-page/  the Checkout COD page
 *
 * Both pages load the same bytes, so neither can drift from the other: the
 * checkout page used to carry its own, slightly different, copy of the same
 * idea and the two diverged visually.
 *
 * The field is a label above a bordered box holding a small icon and the
 * input. It carries no shadow, no gradient, no transition and no hover
 * state — the only state change is the border's colour on focus and on
 * error — so nothing in the form moves after first paint. Colours that are
 * the store's, rather than the component's, are read from --casablanca-brand.
 *
 * Selectors are deliberately unscoped: the product form nests these classes
 * under .casablanca-modular-checkout-wrapper, the checkout page does not, and the
 * classes appear nowhere else in the theme. This sheet is only ever enqueued
 * on those two pages.
 *
 * Adding a rule here changes BOTH forms. Anything that should apply to only
 * one of them belongs in that module's own sheet.
 */

/* ── Field ────────────────────────────────────────────────────────────
   A label above the input, and a small icon INSIDE the input on the
   leading edge.

   What this replaced: a 42px tinted icon column with a border of its own,
   sitting beside a 42px input whose placeholder was doing the label's job.
   The column spent a third of the field's width on decoration, and the
   only statement of what a field was for disappeared the moment the
   customer typed into it.

   Every colour here is a flat token and every state is a border colour:
   no shadow, no gradient, no transition and no hover state, so nothing
   about the field moves or repaints except when it takes focus — and
   focus only swaps the border's colour, which cannot reflow anything.

   The brand colour is read from --casablanca-brand, the variable
   customize_css() prints on :root from the Customizer, so a store's own
   colour reaches the focus ring, the label's asterisk and the icon
   without a hex being written here. The hex in each var() is only the
   fallback for a page served before that block. */

/* ── Radius scope: the forms keep their own corners ─────────────────────
   Site Identity → Appearance → Corner Radius changes --casablanca-radius for
   the whole store — EXCEPT here. The product page's COD form (inline, or in
   the popup), the popup shell and its trigger, the Add to Cart button beside
   it, and the Checkout COD page have their own radius controls (Checkout
   Form → Form Style / Buttons Style), so the global value must not reach
   them. The token is pinned back to the 5px these were designed at.

   Every alias is restated, not just the base: --theme-radius, --radius-* and
   --casablanca-radius-* are computed on :root and inherited already resolved
   to the global value, so re-pointing --casablanca-radius alone would not
   reach the many rules that read an alias. --cod-radius (the fields, 2×) is
   declared below on .casablanca-cod-field, i.e. inside this scope, so it
   follows the pinned value by itself. */
.casablanca-modular-checkout-wrapper,
.casablanca-cod-modal-dialog,
.casablanca-cod-popup-trigger,
.casablanca-atc-wrap,
.casablanca-checkout {
    --casablanca-radius: 5px;
    --casablanca-radius-sm: 5px;
    --casablanca-radius-md: 5px;
    --casablanca-radius-lg: 5px;
    --theme-radius: 5px;
    --radius-sm: 5px;
    --radius-md: 5px;
}

.casablanca-cod-field {
    /* Tokens are declared on the wrapper so both consumers inherit one
       set, and each use restates its fallback for any markup that renders
       .casablanca-checkout-input-group without this wrapper. */
    --cod-border: #DDE3EC;
    --cod-radius: calc(var(--casablanca-radius, 5px) * 2); /* 10px at the default 5px — follows Site Identity → Corner Radius */
    --cod-height: 46px;
    /* The box's inner gutter. Focus reads it back through calc() to keep the
       content still while the border thickens — see :focus-within. */
    --cod-pad: 12px;
    --cod-icon: #8A94A6;
    --cod-label: #1F2937;
    --cod-text: #111827;
    --cod-placeholder: #9AA4B2;
    --cod-accent: var(--casablanca-brand, #531628);
    --cod-error: #dc2626;

    /* The filled field's ground. White here is not a fallback colour to be
       tidied away — it is the value every engine that cannot draw the tint
       CORRECTLY keeps, and the @supports block below is what upgrades it.
       See the "Filled" section for why both features have to be present
       before it may change. */
    --cod-fill: #fff;

    margin: 0;
    text-align: start;
}

.casablanca-cod-field__label {
    display: block;
    margin: 0 0 5px;
    font-family: inherit;
    font-size: 12.5px;
    font-weight: 600;
    line-height: 1.3;
    letter-spacing: 0;
    color: var(--cod-label, #1F2937);
    /* The label is the field's accessible name and its click target; it is
       never a caption to be read past. */
    cursor: pointer;
}

.casablanca-cod-field__required {
    color: var(--cod-accent, var(--casablanca-brand, #531628));
    /* Decorative: `required` on the input is what states the rule to
       assistive technology, and the span carries aria-hidden. */
    margin-inline-start: 2px;
}

.casablanca-checkout-input-group {
    display: flex;
    align-items: center;
    gap: 8px;
    height: var(--cod-height, 46px);
    padding-inline: var(--cod-pad, 12px);
    border: 1px solid var(--cod-border, #DDE3EC);
    border-radius: var(--cod-radius, 10px);
    background: #fff;
    /* The input is a flex child with min-width: 0; nothing can spill out,
       so the box does not need to clip its own content. */
    box-shadow: none;
    /* Restated rather than inherited from base.css's universal rule: the two
       declarations below are only true together. With border-box the box
       keeps its height when the border thickens; the padding calc keeps its
       CONTENTS in place. */
    box-sizing: border-box;
}

/* Focus is the brand colour at 2px, and nothing else — no glow, no shadow,
   no outline offset.
 *
 * Both dimensions are held still rather than left to chance. Vertically the
 * box is border-box at a fixed height, so a thicker border eats into the
 * box instead of growing it, and the row is centred. Horizontally the extra
 * pixel of border is taken back out of the padding — 12px + 1px border
 * becomes 11px + 2px — so the icon and the text the customer is typing do
 * not step sideways at the moment they click in.
 *
 * Written as a calc() off the same --cod-pad the rule above uses, so the
 * mobile override changes one value and both stay in step. */
.casablanca-checkout-input-group:focus-within {
    border-width: 2px;
    border-color: var(--cod-accent, var(--casablanca-brand, #531628));
    padding-inline: calc(var(--cod-pad, 12px) - 1px);
}

/* The icon sits in the flow, not absolutely positioned, so it follows the
   writing direction in RTL with no second rule. */
.casablanca-icon-section {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: none;
    width: auto;
    background: none;
    border: 0;
    /* Muted by default: the icon is a hint about the field, not its
       subject. It picks up the brand colour only while the customer is in
       the field. */
    color: var(--cod-icon, #8A94A6);
}

.casablanca-checkout-input-group:focus-within .casablanca-icon-section {
    color: var(--cod-accent, var(--casablanca-brand, #531628));
}

/* Deliberately no `fill`/`stroke` here. These icons are mixed — city,
   phone and address are stroked over fill="none", user is a filled path —
   and get_svg() rewrites each file's own colour attribute to
   currentColor. Setting `fill: none` on the <svg>, as this rule used to,
   overrode user.svg's inherited fill and drew nothing at all. `color` on
   the wrapper feeds both kinds correctly. */
.casablanca-checkout-input-group .casablanca-icon-section svg {
    width: 17px;
    height: 17px;
    display: block;
}

/* !important throughout: WooCommerce's own form styles and several plugins
   set border/background/padding on bare `input`, and this box draws its
   border on the wrapper instead. */
.casablanca-checkout-input-group input {
    flex: 1;
    min-width: 0;
    border: none !important;
    background: transparent !important;
    padding: 0 !important;
    font-family: inherit;
    /* 16px is not a typographic choice — anything smaller makes iOS Safari
       zoom the viewport when the field takes focus. */
    font-size: 16px !important;
    font-weight: 500;
    line-height: 1.2;
    color: var(--cod-text, #111827) !important;
    outline: none !important;
    box-shadow: none !important;
    height: 100% !important;
    margin: 0 !important;
    /* Follow the form's direction. Chrome's UA sheet pins type="tel" to
       `direction: ltr`, which left the phone placeholder on the left of an
       RTL form while the other fields sat on the right. The digits are an
       LTR run either way, so the number itself still reads 06… */
    direction: inherit;
    text-align: start;
}

.casablanca-checkout-input-group input::placeholder {
    color: var(--cod-placeholder, #9AA4B2);
    font-weight: 400;
    /* Firefox dims placeholders by default; the colour above is the whole
       statement. */
    opacity: 1;
}

/* ── Filled ───────────────────────────────────────────────────────────
   A field holding a value carries a whisper of the store's own colour, so
   the customer can see at a glance what is already answered. It is the
   ground that changes and nothing else: the border stays the neutral 1px
   until the field is focused, the text keeps its colour, the icon is
   untouched and no dimension moves.

   The tint is painted on the WRAPPER, not the input, so it covers the box
   uniformly — icon, gutter and text on one continuous ground. The input is
   transparent over it.

   It is opaque on purpose, mixed against #fff rather than left as an alpha
   over whatever is behind. The autofill rules below have to repaint this
   exact colour INSIDE the input (that is the only way to displace Chrome's
   own background), and a translucent fill there would let the engine's blue
   blend through it. One opaque token, used in both places, is what makes
   the two agree.

   Both features are required before the token changes, because each alone
   would be worse than plain white:

     - without color-mix() there is no colour to use;
     - without :has() the wrapper could not be tinted at all, so an
       autofilled field would show a tinted input inside a white box — the
       icon area a different colour from the rest. Exactly the seam this
       component exists to avoid.

   An engine missing either keeps a white field, which is correct, plain,
   and still free of the browser's blue.

   `:not(:placeholder-shown)` is the test for "has a value", and it relies
   on every field having a non-empty placeholder — CodFields\placeholders()
   guarantees one, including when a filter answers with a blank. */

@supports (background: color-mix(in srgb, red 6%, white)) and selector(:has(input)) {
    .casablanca-cod-field {
        --cod-fill: color-mix(in srgb, var(--cod-accent, var(--casablanca-brand, #531628)) 6%, #fff);
    }

    .casablanca-checkout-input-group:has(input:not(:placeholder-shown)) {
        background: var(--cod-fill, #fff);
    }
}

/* ── Autofill ─────────────────────────────────────────────────────────
   A field the browser fills in must look exactly like a field the
   customer typed into: white box, neutral 1px border, theme text.

   Left alone it does not. Chrome and Safari paint an autofilled input
   pale blue and recolour its text, and Firefox applies a filter that
   tints the whole control. On a COD form that is the first thing a
   returning customer sees — three of the four fields highlighted as
   though something were wrong with them — and it is the one state no
   amount of `background` on the input can answer: the autofill colour is
   applied by the engine itself and outranks an author declaration,
   !important included.

   The inset box-shadow below is the one declaration it does yield to. It
   is NOT a shadow in the design sense and draws nothing of its own: it
   fills the input's box with --cod-fill — the very colour the wrapper is
   already painted, since an autofilled field is by definition a filled one
   — flat, with no blur, no spread beyond the box and no offset. The seam
   that would give it away is exactly what sharing that one token prevents.
   The component still has no visible shadow anywhere. The rejected
   alternative is the `transition: background-color 600000s` trick, which
   is a transition — this form has none, and it only postpones the colour
   rather than replacing it.

   Text needs its own property: -webkit-text-fill-color outranks `color`
   on an autofilled input, so `color` alone would leave the text in
   whatever the engine chose.

   The two blocks are NOT merged into one selector list. An unknown
   selector invalidates a whole CSS rule, and no engine knows both names:
   Firefox would drop a list containing :-webkit-autofill, and older
   WebKit a list containing :autofill.

   The filled state is the section above; what it does NOT touch is the
   border. A field that holds a value keeps the neutral 1px, and the brand
   2px means one thing only: this is the field you are in. */

.casablanca-checkout-input-group input:-webkit-autofill,
.casablanca-checkout-input-group input:-webkit-autofill:hover,
.casablanca-checkout-input-group input:-webkit-autofill:focus,
.casablanca-checkout-input-group input:-webkit-autofill:active {
    box-shadow: inset 0 0 0 100px var(--cod-fill, #fff) !important;
    -webkit-box-shadow: inset 0 0 0 100px var(--cod-fill, #fff) !important;
    -webkit-text-fill-color: var(--cod-text, #111827) !important;
    caret-color: var(--cod-text, #111827);
    background-color: var(--cod-fill, #fff) !important;
    background-image: none !important;
    border: none !important;
    /* Chrome restyles the text on autofill; keep the field's own weight. */
    font-size: 16px !important;
    font-weight: 500;
}

/* The standard pseudo-class: Firefox (where `filter` is the tint to
   clear) and current Chrome/Safari, which apply both names. */
.casablanca-checkout-input-group input:autofill,
.casablanca-checkout-input-group input:autofill:hover,
.casablanca-checkout-input-group input:autofill:focus,
.casablanca-checkout-input-group input:autofill:active {
    box-shadow: inset 0 0 0 100px var(--cod-fill, #fff) !important;
    -webkit-text-fill-color: var(--cod-text, #111827) !important;
    caret-color: var(--cod-text, #111827);
    background-color: var(--cod-fill, #fff) !important;
    background-image: none !important;
    border: none !important;
    filter: none !important;
    font-size: 16px !important;
    font-weight: 500;
}

/* Safari draws its own autofill button INSIDE the input, at the trailing
   edge — the opposite end from the theme's icon, which is a sibling of the
   input and is not touched by any of this. The button is a masked image, so
   background-color is what tints it; left alone it arrives in the system
   blue that the rest of this rule set exists to remove. */
.casablanca-checkout-input-group input::-webkit-contacts-auto-fill-button,
.casablanca-checkout-input-group input::-webkit-credentials-auto-fill-button {
    background-color: var(--cod-icon, #8A94A6);
    margin-inline-start: 4px;
}

.casablanca-checkout-input-group.has-error {
    border-color: var(--cod-error, #dc2626) !important;
}

.casablanca-field-error-message {
    color: var(--cod-error, #dc2626);
    font-size: 12px;
    font-weight: 600;
    line-height: 1.35;
    margin-top: 5px;
    margin-bottom: 0;
    margin-inline-start: 2px;
    display: block !important;
    text-align: start;
    width: 100%;
}

.casablanca-field-error-message:empty {
    display: none !important;
}

/* ── CTA ──────────────────────────────────────────────────────────────
   Colour, border and radius come from the .casablanca-btn contract in
   assets/css/base.css, which lists .casablanca-confirm-checkout-btn by name.
   Only size, the two-line content block and the loading state live here. */

.casablanca-confirm-checkout-btn {
    margin-top: 4px;
    /* Customizer → Checkout Form → Order Button. Colour goes through the
       button contract's own hook in base.css (--ostore-button-bg / -hover /
       -pressed), so hover and pressed keep working; each falls back to the
       contract's value, so nothing changes until a colour is picked. The
       text colour must out-rank the contract's `color: … !important`, which
       this sheet does by loading after base.css. Out-of-stock and disabled
       states keep their own, more specific rules. */
    --ostore-button-bg: var(--casablanca-order-button-bg, var(--ostore-primary));
    --ostore-button-bg-hover: var(--casablanca-order-button-bg-hover, var(--ostore-primary-hover));
    --ostore-button-bg-pressed: var(--casablanca-order-button-bg-hover, var(--ostore-primary-hover));
    color: var(--casablanca-order-button-color, var(--color-bg-white)) !important;

    /* Customizer → Checkout Form → Buttons → Order Button Style. Each value
       falls back to exactly what the .casablanca-btn contract in base.css
       draws, so nothing moves until a control is used. Border and radius
       carry !important only to out-rank that contract's own. Width never
       exceeds the column (max-width), and a narrowed button becomes a block
       flex box (--…-display) so the auto margins can centre it. */
    display: var(--casablanca-order-button-display, inline-flex);
    width: var(--casablanca-order-button-width, 100%);
    max-width: 100%;
    margin-inline: auto;
    min-height: var(--casablanca-order-button-height, 44px);
    border-color: var(--casablanca-order-button-border, color-mix(in srgb, var(--qt-action-bg) 70%, transparent)) !important;
    border-radius: var(--casablanca-order-button-radius, var(--theme-radius, var(--radius-md))) !important;
    box-shadow: var(--casablanca-order-button-shadow, none);
}

/* The contract repaints the border on hover / press with rules one class
   more specific than the one above; a chosen border colour holds through
   both. Unset, these resolve to the contract's own values. */
.casablanca-confirm-checkout-btn:hover {
    border-color: var(--casablanca-order-button-border, color-mix(in srgb, var(--qt-action-hover) 70%, transparent)) !important;
}

.casablanca-confirm-checkout-btn:active {
    border-color: var(--casablanca-order-button-border, color-mix(in srgb, var(--qt-action-pressed) 70%, transparent)) !important;
}

.casablanca-confirm-checkout-btn .casablanca-btn-content {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
}

.casablanca-confirm-checkout-btn svg {
    width: var(--casablanca-icon-size-xl);
    height: var(--casablanca-icon-size-xl);
    stroke: none;
    fill: currentColor;
    color: var(--casablanca-order-button-color, #fff);
    flex-shrink: 0;
}

.casablanca-confirm-checkout-btn .casablanca-btn-text {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    text-align: start;
}

.casablanca-confirm-checkout-btn .casablanca-main-text {
    font-size: 0.9rem;
    font-weight: 800;
    text-transform: uppercase;
    line-height: 1;
}

.casablanca-confirm-checkout-btn .casablanca-sub-text {
    font-size: 0.7rem;
    opacity: 0.9;
    font-weight: 400;
    margin-top: 1px;
}

/* ── CTA loading state ────────────────────────────────────────────────
   The product form's JS toggles `.loading`, the checkout page's toggles
   `.is-loading`. Both are honoured rather than renaming one and having to
   touch the other module's script. */

.casablanca-confirm-checkout-btn.loading,
.casablanca-confirm-checkout-btn.is-loading {
    position: relative;
    cursor: not-allowed;
    pointer-events: none;
}

.casablanca-confirm-checkout-btn.loading .casablanca-btn-content,
.casablanca-confirm-checkout-btn.is-loading .casablanca-btn-content {
    visibility: hidden;
    opacity: 0;
}

.casablanca-confirm-checkout-btn.loading::after,
.casablanca-confirm-checkout-btn.is-loading::after {
    content: "";
    position: absolute;
    width: 20px;
    height: 20px;
    top: calc(50% - 10px);
    inset-inline-start: calc(50% - 10px);
    border: 2.5px solid rgba(255, 255, 255, 0.3);
    border-radius: var(--casablanca-radius-circle, 50%);
    border-top-color: #fff;
    animation: casablanca-spin 0.6s linear infinite;
}

@keyframes casablanca-spin {
    to { transform: rotate(360deg); }
}

/* ── CTA animation ────────────────────────────────────────────────────
   Customizer → CASABLANCA - Checkout Form → "Button Animation".

   The setting is older than these rules and, until they existed, did
   nothing whatsoever: the product form printed `anim-{value}` and no
   stylesheet in the theme declared `.anim-shake` or any of its siblings.
   The class list is now CASABLANCA\WooCommerce\CodButton\animations() — one
   registry behind the control's choices, the sanitizer's allow-list and
   the blocks below. An entry there with no block here is an option that
   does nothing; keep the two in step.

   Rules every one of them follows:

   - ANIMATE ONLY transform, opacity and box-shadow. Those three are
     composited: they never re-run layout, so nothing on the page can move
     because the button is breathing. Nothing here may animate width,
     height, margin, padding or a border.

   - Transforms stay under ~1.5% and ~5px. The button is width: 100%
     inside a padded form, and a transform DOES contribute to an
     ancestor's scrollable overflow — an enthusiastic scale is a
     horizontal scrollbar on a phone.

   - Every animation rests. A loop that never stops is exhausting to sit
     next to and, on a page the customer is reading, reads as a fault
     rather than an invitation; the motion happens in the first fraction
     of a long cycle and the button is still for the rest of it.

   - The whole section is inside prefers-reduced-motion: no-preference.
     A customer who has asked their device for less movement gets a
     button that never moves — not a shorter animation.

   "None" has no rule at all: it is the absence of a class, so a store
   that wants a still button ships no animation CSS for that button. */

@media (prefers-reduced-motion: no-preference) {

    /* Shake — a short rock, then a long pause. Horizontal only, ±4px. */
    .casablanca-confirm-checkout-btn.casablanca-anim-shake {
        animation: casablanca-cta-shake 3.2s ease-in-out infinite;
    }

    @keyframes casablanca-cta-shake {
        0%, 12%, 100% { transform: translate3d(0, 0, 0); }
        2%            { transform: translate3d(-4px, 0, 0); }
        4%            { transform: translate3d(4px, 0, 0); }
        6%            { transform: translate3d(-3px, 0, 0); }
        8%            { transform: translate3d(3px, 0, 0); }
        10%           { transform: translate3d(-1px, 0, 0); }
    }

    /* Pulse — one heartbeat per cycle. */
    .casablanca-confirm-checkout-btn.casablanca-anim-pulse {
        animation: casablanca-cta-pulse 2.4s ease-in-out infinite;
    }

    @keyframes casablanca-cta-pulse {
        0%, 40%, 100% { transform: scale3d(1, 1, 1); }
        12%           { transform: scale3d(1.015, 1.015, 1); }
        24%           { transform: scale3d(1, 1, 1); }
        32%           { transform: scale3d(1.01, 1.01, 1); }
    }

    /* Bounce — a hop of 5px, landing with a small settle. */
    .casablanca-confirm-checkout-btn.casablanca-anim-bounce {
        animation: casablanca-cta-bounce 2.6s cubic-bezier(0.28, 0.84, 0.42, 1) infinite;
    }

    @keyframes casablanca-cta-bounce {
        0%, 30%, 100% { transform: translate3d(0, 0, 0); }
        10%           { transform: translate3d(0, -5px, 0); }
        18%           { transform: translate3d(0, 0, 0); }
        23%           { transform: translate3d(0, -2px, 0); }
    }

    /* Scale — a slow breath, the calmest of the set. No rest: it is
       already continuous and gentle enough to read as ambient. */
    .casablanca-confirm-checkout-btn.casablanca-anim-scale {
        animation: casablanca-cta-scale 3s ease-in-out infinite;
    }

    @keyframes casablanca-cta-scale {
        0%, 100% { transform: scale3d(1, 1, 1); }
        50%      { transform: scale3d(1.012, 1.012, 1); }
    }

    /* Tada — the loudest: a wobble with a little rotation. Kept to 1.5°
       and 1.5% so a full-width button does not look like it is falling
       over. */
    .casablanca-confirm-checkout-btn.casablanca-anim-tada {
        animation: casablanca-cta-tada 3.4s ease-in-out infinite;
    }

    @keyframes casablanca-cta-tada {
        0%, 20%, 100% { transform: scale3d(1, 1, 1) rotate(0deg); }
        3%            { transform: scale3d(0.99, 0.99, 1) rotate(-1.5deg); }
        6%, 12%       { transform: scale3d(1.015, 1.015, 1) rotate(1.5deg); }
        9%, 15%       { transform: scale3d(1.015, 1.015, 1) rotate(-1.5deg); }
        18%           { transform: scale3d(1, 1, 1) rotate(0deg); }
    }

    /* Glow — the one animation that is not a transform. box-shadow is
       composited too, and because the shadow is drawn OUTSIDE the border
       box it moves nothing either. Brand-coloured, via the same
       --casablanca-brand-rgb customize_css() prints beside --casablanca-brand. */
    .casablanca-confirm-checkout-btn.casablanca-anim-glow {
        animation: casablanca-cta-glow 2.4s ease-in-out infinite;
    }

    @keyframes casablanca-cta-glow {
        0%, 100% { box-shadow: 0 0 0 0 rgba(var(--casablanca-brand-rgb, 83, 22, 40), 0.35); }
        50%      { box-shadow: 0 0 0 6px rgba(var(--casablanca-brand-rgb, 83, 22, 40), 0); }
    }

    /* Shimmer — a highlight sweeping across the face.

       It is drawn on ::before, NOT ::after: ::after is the loading
       spinner (see the CTA loading state above), and one pseudo-element
       cannot be both. The button already carries `position: relative` and
       `overflow: hidden` from the .casablanca-btn contract in base.css, which
       is what clips the sweep to the button's rounded corners — this rule
       adds neither, so it cannot change the button's box.

       inset-inline-start rather than left, and a translate rather than a
       position change, so the sweep runs with the writing direction and
       is composited. */
    .casablanca-confirm-checkout-btn.casablanca-anim-shimmer::before {
        content: "";
        position: absolute;
        top: 0;
        bottom: 0;
        inset-inline-start: -60%;
        width: 40%;
        pointer-events: none;
        background: linear-gradient(
            100deg,
            rgba(255, 255, 255, 0) 0%,
            rgba(255, 255, 255, 0.28) 50%,
            rgba(255, 255, 255, 0) 100%
        );
        animation: casablanca-cta-shimmer 3.4s ease-in-out infinite;
    }

    @keyframes casablanca-cta-shimmer {
        0%, 100% { transform: translate3d(0, 0, 0); }
        45%      { transform: translate3d(400%, 0, 0); }
    }
}

/* A button that cannot be pressed does not beckon.

   Three states, all of which can be true while an animation class is on
   the element: the two loading flags the two flows toggle, a disabled
   button, and the out-of-stock latch. `animation: none` is the whole
   answer — the class stays where it is and the motion simply stops, so
   nothing has to be added or removed by a script.

   Outside the reduced-motion query on purpose: it must hold whatever the
   customer's motion preference is. */
.casablanca-confirm-checkout-btn.loading,
.casablanca-confirm-checkout-btn.is-loading,
.casablanca-confirm-checkout-btn:disabled,
.casablanca-confirm-checkout-btn.is-permanently-disabled {
    animation: none !important;
}

.casablanca-confirm-checkout-btn.loading::before,
.casablanca-confirm-checkout-btn.is-loading::before,
.casablanca-confirm-checkout-btn:disabled::before,
.casablanca-confirm-checkout-btn.is-permanently-disabled::before {
    animation: none !important;
    opacity: 0;
}

/* ── Mobile ───────────────────────────────────────────────────────────
   The field stays full width and keeps a comfortable tap target: 44px is
   the minimum a finger needs, and the 16px input size is what stops iOS
   zooming the viewport on focus. Only the box's height and its inner
   gutter tighten — the icon and the label keep their size, because a
   phone is where this form is actually read.

   --cod-pad is overridden as a token, so the :focus-within calc() follows
   it without a second rule. */

@media (max-width: 767px) {
    .casablanca-cod-field {
        --cod-height: 44px;
        --cod-pad: 11px;
    }

    .casablanca-cod-field__label {
        font-size: 12px;
        margin-bottom: 4px;
    }

    /* !important here only outranks the .casablanca-btn contract in base.css,
       which declares size and radius with !important of its own. Nothing
       about the button's colour or border is overridden. */
    .casablanca-confirm-checkout-btn {
        min-height: var(--casablanca-order-button-height, 40px) !important;
        padding: 8px 14px !important;
        border-radius: var(--casablanca-order-button-radius, var(--casablanca-radius)) !important;
    }

    .casablanca-confirm-checkout-btn .casablanca-main-text {
        font-size: 0.8rem !important;
        font-weight: 600 !important;
        letter-spacing: 0.3px;
    }

    .casablanca-confirm-checkout-btn .casablanca-sub-text {
        font-size: 0.65rem !important;
    }

    .casablanca-confirm-checkout-btn svg {
        width: var(--casablanca-icon-size-lg) !important;
        height: var(--casablanca-icon-size-lg) !important;
        stroke: none !important;
        fill: currentColor !important;
    }
}

@media (prefers-reduced-motion: reduce) {
    .casablanca-confirm-checkout-btn.loading::after,
    .casablanca-confirm-checkout-btn.is-loading::after { animation-duration: 2s; }
}
