/**
 * Kiosk
 *
 * @copyright   Copyright (c) 2026 Jeroen Moolenschot | Joomill
 * @license     GNU General Public License version 3 or later; see LICENSE
 * @link        https://www.joomill-kiosk.com
 */

/*
 * Modest, layout-neutral styling for the checkout and order pages,
 * scoped to the "none" framework mode: spacing and typography only, no
 * positioning framework and no opinion on the surrounding site's grid/theme
 * colours.
 *
 * Everything below is scoped under `.com-kiosk-checkout--plain` or
 * `.com-kiosk-order--plain` -- the class `tmpl/checkout/default.php` and
 * `tmpl/order/default.php` only add when `$ui->is(Ui::NONE)` -- so none of
 * it collides with Bootstrap's or UIkit's own card/form styling in the two
 * framework modes (this stylesheet still loads in all three modes; the
 * scope is what makes it inert in the other two). A few things stay outside
 * that scope on purpose, and are called out where they live below: the
 * `[hidden]` safety net, the sticky rule and the two-column grid for
 * `.com-kiosk-checkout__aside`/`__columns`, the payment tile grid
 * (`.com-kiosk-payment__options` and friends), `.com-kiosk-sr-only`, and
 * three structural rules (offer list, field spacing, block spacing) that
 * neither framework resets or provides on its own.
 *
 * `[hidden]` is left almost entirely to the browser's native user-agent rule
 * (`display: none`) -- nothing below ever sets `display` on `.com-kiosk-field`,
 * `#kiosk-error-summary`, or any other element that can carry the `hidden`
 * attribute. An author rule that sets `display` on such an element would win
 * the cascade over the user-agent's `[hidden]` rule regardless of selector
 * specificity (origin order beats specificity), which would silently defeat
 * both the no-JS server-side hiding and checkout.js's live condition
 * toggling (the wrapper [hidden] stays native, never fought with CSS). This is
 * exactly the rule `tests/Unit/Site/LayoutClassGuardTest.php`'s Guard B (the
 * `.com-kiosk-field` wrapper) and Guard C (`#kiosk-error-summary`) exist to
 * enforce on the markup side -- see that test's own docblock. The one
 * exception is the generic `[hidden]` safety net right below, which only
 * ever pushes `display` toward `none` and so can never fight that rule --
 * see its own comment for why it exists at all.
 */

/*
 * A generic safety net for every
 * `[hidden]` element inside the checkout or the order page, in every mode --
 * deliberately outside the `--plain` scope, because the two framework modes
 * need it too.
 *
 * `[hidden]` alone stops working the moment a class on the same element also
 * sets `display`, because an author rule beats the user-agent `[hidden]`
 * rule regardless of specificity (origin order wins). Bootstrap never
 * triggers this: Reboot itself ships `[hidden] { display: none !important; }`,
 * so no Bootstrap class can ever win. UIkit does trigger it -- its own
 * `[hidden]` normalize rule carries no `!important` and is declared before
 * its component rules, so on source order alone `.uk-button`'s
 * `display: inline-block` beats `[hidden]`. Concretely: `submit.php`'s
 * update button (`buttonSecondary()`) stays visible on a YOOtheme template
 * even after `checkout.js` sets `updateButton.hidden = true` the instant it
 * activates. `customer.php`'s `.com-kiosk-address` fieldset (hidden when no
 * sub-field in that block applies to the entered country) is a third element
 * this net was not written for specifically but happens to cover as well.
 *
 * This rule only ever pushes `display` toward `none`, never the other way,
 * so it cannot break the [hidden]-versus-display agreement documented above
 * -- it can only backstop the cases a per-role guard misses.
 */
.com-kiosk-checkout [hidden],
.com-kiosk-order [hidden] {
    display: none !important;
}

/*
 * Three rules that were scoped under
 * `--plain` but never should have been, because neither framework resets or
 * provides them on its own -- none of the three sets `display`, so all three
 * are as safe outside the scope as the `[hidden]` net above.
 *
 * - `.com-kiosk-offer`: neither Bootstrap nor UIkit resets a bare `<ul>`, so
 *   the offer list gets bullets and indentation in both framework modes (and
 *   the grid layout's items keep their markers too).
 * - `.com-kiosk-field`: no framework layout writes a spacing utility on this
 *   wrapper on purpose (the field wrapper never carries a framework class at
 *   all, see this file's own [hidden] discussion above), so without this
 *   rule fields render glued together in both framework modes.
 * - `.com-kiosk-block`: Bootstrap's `.card` carries no `margin-bottom` of its
 *   own, so the block cards stack seamlessly on top of each other; this rule
 *   and a block's own bottom-most element (its fieldset in the none mode)
 *   collapse into one margin rather than stacking, so it does not double the
 *   gap the `--plain` scope already gives a fieldset below.
 */
.com-kiosk-offer {
    margin: 0;
    padding: 0;
    list-style: none;
}

.com-kiosk-field {
    margin-bottom: 1rem;
}

.com-kiosk-block {
    margin-bottom: 1.5rem;
}

.com-kiosk-checkout--plain.com-kiosk-checkout {
    max-width: 100%;
}

.com-kiosk-checkout--plain .com-kiosk-checkout__title {
    margin: 0 0 1em;
}

.com-kiosk-checkout--plain .com-kiosk-checkout__form fieldset {
    margin: 0 0 1.5em;
    padding: 1em;
    border: 1px solid rgba(0, 0, 0, 0.15);
}

.com-kiosk-checkout--plain .com-kiosk-checkout__form legend {
    padding: 0 0.5em;
    font-weight: 600;
}

.com-kiosk-checkout--plain .com-kiosk-field label {
    display: block;
    margin-bottom: 0.25em;
}

.com-kiosk-checkout--plain .com-kiosk-field__group label {
    margin-bottom: 0.25em;
}

.com-kiosk-checkout--plain .com-kiosk-field__required {
    color: #b3261e;
}

.com-kiosk-checkout--plain .com-kiosk-field__description {
    margin: 0.25em 0;
    font-size: 0.875em;
    opacity: 0.8;
}

/*
 * The fallback grid rules for the "grid" layout in the none mode -- the
 * framework modes get their N-up layout from $ui->grid()/gridItem() instead
 * (see `layouts/checkout/offer.php`'s own docblock). The
 * `--grid-N` modifier carries the per-checkout column count (`OfferGrid`);
 * below Bootstrap's own `md` tier (48rem / 768px) everything stays a single
 * column, matching the framework modes' breakpoint.
 */
.com-kiosk-checkout--plain .com-kiosk-offer--grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 1.5rem;
}

@media (min-width: 48rem) {
    .com-kiosk-checkout--plain .com-kiosk-offer--grid-2 {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .com-kiosk-checkout--plain .com-kiosk-offer--grid-3 {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }

    .com-kiosk-checkout--plain .com-kiosk-offer--grid-4 {
        grid-template-columns: repeat(4, minmax(0, 1fr));
    }
}

/* Spacing only: the card look itself is the mode-independent tile design
   at the bottom of this file. */
.com-kiosk-checkout--plain .com-kiosk-offer__item {
    margin: 0 0 1rem;
}

.com-kiosk-checkout--plain .com-kiosk-offer__title {
    font-weight: 600;
}

.com-kiosk-checkout--plain .com-kiosk-offer__options {
    margin-top: 0.75em;
}

.com-kiosk-checkout--plain .com-kiosk-totals__lines {
    width: 100%;
    border-collapse: collapse;
}

.com-kiosk-checkout--plain .com-kiosk-totals__lines th,
.com-kiosk-checkout--plain .com-kiosk-totals__lines td {
    padding: 0.4em 0.6em;
    text-align: left;
    border-bottom: 1px solid rgba(0, 0, 0, 0.1);
}

/*
 * The amount column, right
 * aligned -- `totals.php` already asks for `$ui->textEnd()` on it, which is
 * empty in the none mode, exactly like `.com-kiosk-order__items` handles its
 * own last column below. Without this the checkout was the one page of the
 * two that left its amounts left-aligned.
 */
.com-kiosk-checkout--plain .com-kiosk-totals__lines td:last-child,
.com-kiosk-checkout--plain .com-kiosk-totals__lines th:last-child {
    text-align: right;
}

.com-kiosk-checkout--plain .com-kiosk-totals__grand-total {
    margin-top: 1em;
    font-weight: 600;
    font-size: 1.1em;
}

.com-kiosk-checkout--plain .com-kiosk-totals__reverse-charge {
    font-size: 0.875em;
    opacity: 0.8;
}

.com-kiosk-checkout--plain .com-kiosk-error-summary {
    margin-bottom: 1em;
    padding: 0.75em 1em;
    border: 1px solid #b3261e;
    color: #b3261e;
}

/*
 * Outside the plain scope on purpose, like `.com-kiosk-sr-only`: the
 * per-field error and both error icons render identically in every
 * framework mode -- a validation error must carry an icon plus text, never
 * colour alone (build document ch. 20), whichever framework styles the rest
 * of the form. #b3261e on white is 6.6:1, comfortably past the 4.5:1 text
 * minimum.
 */
.kiosk-field-error {
    display: flex;
    align-items: flex-start;
    gap: 0.375em;
    margin: 0.25em 0 0.5em;
    color: #b3261e;
    font-size: 0.875em;
}

.kiosk-field-error__icon {
    flex: none;
    margin-top: 0.125em;
}

/*
 * Live VIES status under the VAT number field (checkout.js). Same contrast
 * rule as .kiosk-field-error: the state is also in the text, never colour
 * alone. #1d7a46 and #b3261e on white both clear the 4.5:1 text minimum.
 */
.com-kiosk-vies-status {
    margin: 0.25em 0 0.5em;
    font-size: 0.875em;
    color: var(--kiosk-muted, #4b5563);
}

.com-kiosk-vies-status[data-state="valid"] {
    color: #1d7a46;
}

.com-kiosk-vies-status[data-state="invalid"] {
    color: #b3261e;
}

.com-kiosk-error-summary__icon {
    display: inline-block;
    vertical-align: -0.125em;
    margin-right: 0.25em;
}

/*
 * Outside the plain scope on purpose: `Ui::none()->srOnly()` returns this
 * class for the none mode, and checkout.js falls back to it too whenever a
 * template override predates this change and never passed a
 * `data-kiosk-ui-sr-only` value at all -- both callers need it to work
 * regardless of whether `.com-kiosk-checkout--plain` is present on the page.
 */
.com-kiosk-sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/*
 * Focus-visible outline is preserved everywhere -- never removed without a
 * replacement. This rule only strengthens the browser default's
 * visibility, it never suppresses it.
 */
.com-kiosk-checkout--plain .com-kiosk-checkout__form :focus-visible {
    outline: 2px solid #1a56db;
    outline-offset: 2px;
}

.com-kiosk-checkout--plain .com-kiosk-submit__update {
    margin-right: 0.5em;
}

.com-kiosk-checkout--plain .com-kiosk-submit__disabled-notice {
    font-size: 0.875em;
    opacity: 0.8;
}

/*
 * Outside the plain scope on purpose: the aside is a Kiosk-owned element in
 * every mode, Bootstrap's sticky utility does not exist in UIkit (uk-sticky
 * is JavaScript-driven), and this rule sets no display, so it cannot defeat
 * the native [hidden] handling documented at the top of this file.
 */
.com-kiosk-checkout__aside {
    position: sticky;
    top: 1rem;
}

/*
 * The none mode's own two-column
 * grid. `DefaultCheckoutRenderer` has emitted `.com-kiosk-checkout__columns`
 * around the main and aside blocks from the start, but nothing here ever
 * gave the class meaning, so an administrator's per-block column choice did
 * nothing on a template with no framework -- the same shape of dead class
 * this whole feature set out to remove. Bootstrap and UIkit need no help
 * here; they get their layout from `$ui->grid()`/`colMain()`/`colAside()`
 * instead, which is why this stays inside the `--plain` scope.
 *
 * Proportions follow the per-checkout column split the renderer stamps on
 * the wrapper as a `--8-4`-style modifier (`ColumnSplit`); the bare class
 * keeps the 7/5 default so a wrapper without a modifier still lays out.
 * `minmax(0, ...)` on both tracks, not a bare `Nfr`, so a long unbreakable
 * word (an email address, say) cannot force its column wider than its
 * share. The breakpoint matches Bootstrap's own `lg` tier (62rem / 992px),
 * so the two-column layout appears and disappears at the same width
 * regardless of mode.
 */
.com-kiosk-checkout--plain .com-kiosk-checkout__columns {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 1.5rem;
}

@media (min-width: 62rem) {
    .com-kiosk-checkout--plain .com-kiosk-checkout__columns {
        grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
    }

    .com-kiosk-checkout--plain .com-kiosk-checkout__columns--8-4 {
        grid-template-columns: minmax(0, 8fr) minmax(0, 4fr);
    }

    .com-kiosk-checkout--plain .com-kiosk-checkout__columns--6-6 {
        grid-template-columns: minmax(0, 6fr) minmax(0, 6fr);
    }

    .com-kiosk-checkout--plain .com-kiosk-checkout__columns--5-7 {
        grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    }

    .com-kiosk-checkout--plain .com-kiosk-checkout__columns--4-8 {
        grid-template-columns: minmax(0, 4fr) minmax(0, 8fr);
    }
}

/*
 * The payment tile grid is structure, not theme: neither Bootstrap nor UIkit
 * provides it and neither resets it, so this stays outside the
 * `.com-kiosk-checkout--plain` scope and applies in all three framework
 * modes, the same reason `.com-kiosk-checkout__columns` does.
 *
 * The modifier only ever widens the grid above the breakpoint. Below it
 * every checkout is a single column whatever the admin chose: four payment
 * tiles side by side on a phone is unusable. Nothing here sets `display` on
 * an element that can carry `hidden`.
 */
.com-kiosk-payment__options {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 0.5rem;
}

.com-kiosk-payment__option label {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.com-kiosk-payment__logo {
    flex: 0 0 auto;
    width: 2rem;
    height: 2rem;
    object-fit: contain;
}

@media (min-width: 40rem) {
    .com-kiosk-payment__options--cols-2 {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .com-kiosk-payment__options--cols-3 {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }

    .com-kiosk-payment__options--cols-4 {
        grid-template-columns: repeat(4, minmax(0, 1fr));
    }
}

/*
 * The order page's plain-mode styling: same
 * restrained spirit as the checkout's own rules above -- spacing, a light
 * border on the cards, and an aligned amount column -- nothing the
 * framework modes need, since they get card/table/text-alignment roles from
 * $ui instead.
 */
.com-kiosk-order--plain.com-kiosk-order {
    max-width: 100%;
}

.com-kiosk-order--plain .com-kiosk-order__title {
    margin: 0 0 1em;
}

.com-kiosk-order--plain .com-kiosk-order__test-mode {
    margin: 0 0 1em;
    padding: 0.5em 0.75em;
    border: 1px solid rgba(0, 0, 0, 0.15);
}

.com-kiosk-order--plain .com-kiosk-order__processing,
.com-kiosk-order--plain .com-kiosk-order__summary-card,
.com-kiosk-order--plain .com-kiosk-order__payment-instructions,
.com-kiosk-order--plain .com-kiosk-order__overview {
    margin: 0 0 1.5em;
    padding: 1em;
    border: 1px solid rgba(0, 0, 0, 0.15);
}

.com-kiosk-order--plain .com-kiosk-order__summary dt {
    font-weight: 600;
}

.com-kiosk-order--plain .com-kiosk-order__summary dd {
    margin: 0 0 0.5em;
}

.com-kiosk-order--plain .com-kiosk-order__items {
    width: 100%;
    border-collapse: collapse;
}

.com-kiosk-order--plain .com-kiosk-order__items th,
.com-kiosk-order--plain .com-kiosk-order__items td {
    padding: 0.4em 0.6em;
    text-align: left;
    border-bottom: 1px solid rgba(0, 0, 0, 0.1);
}

.com-kiosk-order--plain .com-kiosk-order__items td:last-child,
.com-kiosk-order--plain .com-kiosk-order__items th:last-child {
    text-align: right;
}

.com-kiosk-order--plain .com-kiosk-order__totals {
    margin-top: 1em;
}

.com-kiosk-order--plain .com-kiosk-order__totals dt {
    opacity: 0.8;
}

.com-kiosk-order--plain .com-kiosk-order__totals dd {
    margin: 0 0 0.4em;
    text-align: right;
}

.com-kiosk-order--plain .com-kiosk-order__retry {
    margin-top: 1em;
}

.com-kiosk-order--plain .com-kiosk-order__downloads,
.com-kiosk-order--plain .com-kiosk-order__invoices {
    margin: 0 0 1.5em;
    padding: 1em;
    border: 1px solid rgba(0, 0, 0, 0.15);
}

.com-kiosk-order__invoices-date,
.com-kiosk-order__downloads-expiry {
    margin-left: 0.5em;
    opacity: 0.7;
    font-size: 0.9em;
}

/*
 * The account page's plain-mode styling, the same restrained spirit as the
 * order page above: one bordered card per order, a compact summary list,
 * and muted metadata next to the invoice and download links.
 */
.com-kiosk-account--plain .com-kiosk-account__title {
    margin: 0 0 1em;
}

.com-kiosk-account--plain .com-kiosk-account__order {
    margin: 0 0 1.5em;
    padding: 1em;
    border: 1px solid rgba(0, 0, 0, 0.15);
}

.com-kiosk-account--plain .com-kiosk-account__test-mode {
    margin: 0 0 1em;
    padding: 0.5em 0.75em;
    border: 1px solid rgba(0, 0, 0, 0.15);
}

.com-kiosk-account--plain .com-kiosk-account__summary dt {
    font-weight: 600;
}

.com-kiosk-account--plain .com-kiosk-account__summary dd {
    margin: 0 0 0.5em;
}

.com-kiosk-account__order-title {
    margin: 0 0 0.75em;
    font-size: 1.15em;
}

.com-kiosk-account__block-title {
    margin: 1em 0 0.4em;
    font-size: 1em;
}

.com-kiosk-account__invoice-date,
.com-kiosk-account__download-expiry {
    margin-left: 0.5em;
    opacity: 0.7;
    font-size: 0.9em;
}

.com-kiosk-account__order-link {
    margin: 1em 0 0;
}

/* Product image and description: small thumbnail in the
   list layout, full-width cover in the grid layout. */
.com-kiosk-offer__image {
    display: block;
    max-width: 100%;
    height: auto;
    border-radius: var(--kiosk-radius-sm, 0.375rem);
}

.com-kiosk-offer__image--list {
    max-width: 160px;
}

.com-kiosk-offer__image--grid {
    width: 100%;
    aspect-ratio: 4 / 3;
    object-fit: cover;
}

.com-kiosk-offer__description {
    margin: 0.5em 0 0;
    font-size: 0.9em;
}

.com-kiosk-offer__description > :last-child {
    margin-bottom: 0;
}

/*
 * ---------------------------------------------------------------------------
 * The Kiosk checkout design: white cards with a soft primary border,
 * selectable tiles that fill with the primary colour on hover, a quantity
 * stepper, and a bordered order-summary card. Applies in every Ui mode --
 * these are Kiosk-owned class names, and a template overrides the look by
 * redefining the custom properties below (or any rule) in its own CSS.
 * No rule in this section sets `display` on an element that can carry
 * `[hidden]`.
 * ---------------------------------------------------------------------------
 */
.com-kiosk-checkout {
    --kiosk-primary: var(--bs-primary, #2563eb);
    --kiosk-primary-contrast: #ffffff;
    --kiosk-primary-soft: color-mix(in srgb, var(--kiosk-primary) 20%, transparent);
    --kiosk-primary-tint: color-mix(in srgb, var(--kiosk-primary) 6%, #ffffff);
    /*
     * 75%, not 50%: a focus indicator must reach 3:1 against the page
     * background (WCAG 1.4.11, build document ch. 20); the default primary
     * at 75% over white lands on 3.3:1, at 50% it only reached 2.1:1.
     */
    --kiosk-primary-ring: color-mix(in srgb, var(--kiosk-primary) 75%, transparent);
    --kiosk-card: #ffffff;
    --kiosk-border: #e5e7eb;
    /*
     * Decorative lines (cards, table rules) may stay light, but the border
     * of a form control identifies the control itself and must reach 3:1
     * (WCAG 1.4.11): gray-500 lands on 4.8:1 against white.
     */
    --kiosk-control-border: #6b7280;
    --kiosk-muted: #4b5563;
    --kiosk-radius: 0.5rem;
    --kiosk-radius-sm: 0.375rem;
}

/* --- Product tiles ------------------------------------------------------ */

.com-kiosk-offer__item {
    display: flex;
    flex-direction: column;
    gap: 0.625rem;
    background: var(--kiosk-card);
    border: 1px solid var(--kiosk-primary-soft);
    border-radius: var(--kiosk-radius);
    padding: 1.25rem;
    transition: border-color 0.15s ease-in-out, background-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
}

.com-kiosk-offer__item:hover {
    border-color: var(--kiosk-primary);
}

.com-kiosk-offer__item:has(> label input:checked) {
    border-color: var(--kiosk-primary);
    background: var(--kiosk-primary-tint);
    box-shadow: 0 0 0 1px var(--kiosk-primary);
}

.com-kiosk-offer__item > label {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.625rem;
    cursor: pointer;
    margin: 0;
}

.com-kiosk-offer__item > label input[type="radio"],
.com-kiosk-offer__item > label input[type="checkbox"] {
    accent-color: var(--kiosk-primary);
    width: 1.05rem;
    height: 1.05rem;
    flex-shrink: 0;
    margin: 0;
}

.com-kiosk-offer__title {
    font-weight: 600;
}

/* --- Donation amount buttons -------------------------------------------- */

.com-kiosk-donationamount__choices {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(5.5rem, 1fr));
    gap: 0.5rem;
}

.com-kiosk-donationamount__option {
    position: relative;
    display: block;
    margin: 0;
    cursor: pointer;
}

/*
 * Visually hidden, never display:none: the radio keeps keyboard focus and
 * form semantics; the label below is its visible face.
 */
.com-kiosk-donationamount__radio {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: 0;
    padding: 0;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

.com-kiosk-donationamount__label {
    display: block;
    padding: 0.625rem 0.5rem;
    text-align: center;
    font-weight: 600;
    background: var(--kiosk-card);
    border: 1px solid var(--kiosk-control-border, #6b7280);
    border-radius: var(--kiosk-radius, 0.5rem);
    transition: border-color 0.15s ease-in-out, background-color 0.15s ease-in-out, color 0.15s ease-in-out;
}

.com-kiosk-donationamount__option:hover .com-kiosk-donationamount__label {
    border-color: var(--kiosk-primary);
}

.com-kiosk-donationamount__radio:checked + .com-kiosk-donationamount__label {
    background: var(--kiosk-primary);
    border-color: var(--kiosk-primary);
    color: var(--kiosk-primary-contrast, #ffffff);
}

/*
 * The visible focus ring lands on the label, since the radio itself is
 * clipped away. Transparent outline for forced-colors mode, same reasoning
 * as the form-wide :focus-visible rule.
 */
.com-kiosk-donationamount__radio:focus-visible + .com-kiosk-donationamount__label {
    outline: 2px solid transparent;
    outline-offset: 2px;
    box-shadow: 0 0 0 2px var(--kiosk-primary-ring);
}

.com-kiosk-donationamount__custom-input {
    display: flex;
    align-items: center;
    margin-top: 0.5rem;
    background: var(--kiosk-card);
    border: 1px solid var(--kiosk-control-border, #6b7280);
    border-radius: var(--kiosk-radius-sm, 0.375rem);
}

/*
 * The custom-amount field only shows once "other amount" is the selected
 * choice. Pure CSS, so the reveal works without JavaScript; a browser
 * without :has() simply ignores the rule and keeps the field always
 * visible, which is the safe fallback.
 */
.com-kiosk-donationamount:not(:has(.com-kiosk-donationamount__radio[value="custom"]:checked)) .com-kiosk-donationamount__custom-input {
    display: none;
}

.com-kiosk-donationamount__prefix {
    padding: 0 0.5rem 0 0.75rem;
    color: var(--kiosk-muted, #4b5563);
    font-weight: 600;
}

/* Same metrics as the checkout's other text controls. */
.com-kiosk-donationamount__custom-input input[type="number"] {
    flex: 1 1 auto;
    min-width: 0;
    padding: 0.375rem 0.75rem 0.375rem 0;
    border: 0;
    background: transparent;
}

.com-kiosk-donationamount__custom-input input[type="number"]:focus {
    outline: none;
}

.com-kiosk-donationamount__custom-input:focus-within {
    outline: 2px solid transparent;
    outline-offset: 2px;
    box-shadow: 0 0 0 2px var(--kiosk-primary-ring);
}

.com-kiosk-offer__price {
    display: block;
    font-weight: 600;
    white-space: nowrap;
}

.com-kiosk-offer__compare-price {
    margin-inline-end: 0.5em;
    opacity: 0.7;
}

/*
 * Placement only, and deliberately in every mode: the badge takes its own
 * line above the title. `flex-basis: 100%` forces the wrap, the label
 * carries `flex-wrap: wrap` for it, and `order` is deliberately absent --
 * the badge comes first in the markup too, so a screen reader's reading
 * order matches what the eye sees, which `order` alone cannot do.
 */
.com-kiosk-offer__highlight {
    flex-basis: 100%;
    align-self: flex-start;
}

/*
 * The look is the none mode's business only. In the Bootstrap and UIkit
 * modes `$ui->badge()` puts the framework's own badge class on this
 * element, and painting a second background and radius underneath it would
 * fight whatever the site's theme decided a badge looks like.
 */
.com-kiosk-checkout--plain .com-kiosk-offer__highlight {
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--kiosk-primary-contrast);
    background: var(--kiosk-primary);
    border-radius: 999px;
    padding: 0.125rem 0.625rem;
}

.com-kiosk-offer--list .com-kiosk-offer__item {
    margin-bottom: 0.75rem;
}

.com-kiosk-offer__description {
    color: var(--kiosk-muted);
}

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

.com-kiosk-offer__quantity {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
}

.com-kiosk-offer__quantity-label {
    font-size: 0.875rem;
    color: var(--kiosk-muted);
    margin: 0;
}

.com-kiosk-offer__quantity input[type="number"] {
    width: 4rem;
    height: 2rem;
    text-align: center;
    border: 1px solid var(--kiosk-control-border);
    border-radius: var(--kiosk-radius-sm);
    background: var(--kiosk-card);
    padding: 0 0.25rem;
}

/* The +/- buttons only exist once checkout.js has enhanced the input. */
.com-kiosk-offer__quantity--stepper {
    border: 1px solid var(--kiosk-control-border);
    border-radius: var(--kiosk-radius-sm);
    background: var(--kiosk-card);
    padding: 0.25rem;
    gap: 0.25rem;
}

.com-kiosk-offer__quantity--stepper input[type="number"] {
    border: 0;
    width: 3rem;
    appearance: textfield;
    -moz-appearance: textfield;
}

.com-kiosk-offer__quantity--stepper input[type="number"]::-webkit-outer-spin-button,
.com-kiosk-offer__quantity--stepper input[type="number"]::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

.com-kiosk-qty-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    flex-shrink: 0;
    font-size: 1rem;
    font-weight: 500;
    line-height: 1;
    color: var(--kiosk-primary);
    background: var(--kiosk-card);
    border: 1px solid var(--kiosk-control-border);
    border-radius: var(--kiosk-radius-sm);
    cursor: pointer;
    transition: background-color 0.15s ease-in-out, color 0.15s ease-in-out, border-color 0.15s ease-in-out;
}

.com-kiosk-qty-btn:hover {
    background: var(--kiosk-primary);
    border-color: var(--kiosk-primary);
    color: var(--kiosk-primary-contrast);
}

.com-kiosk-qty-btn:disabled {
    pointer-events: none;
    opacity: 0.5;
}

/* --- Payment method tiles ------------------------------------------------ */

.com-kiosk-payment__option > label {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    background: var(--kiosk-card);
    border: 1px solid var(--kiosk-primary-soft);
    border-radius: var(--kiosk-radius);
    padding: 0.875rem 1rem;
    cursor: pointer;
    margin: 0 0 0.625rem;
    transition: border-color 0.15s ease-in-out, background-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
}

.com-kiosk-payment__option > label:hover {
    border-color: var(--kiosk-primary);
}

.com-kiosk-payment__option > label:has(input:checked) {
    border-color: var(--kiosk-primary);
    background: var(--kiosk-primary-tint);
    box-shadow: 0 0 0 1px var(--kiosk-primary);
}

.com-kiosk-payment__option input[type="radio"] {
    accent-color: var(--kiosk-primary);
    width: 1.05rem;
    height: 1.05rem;
    flex-shrink: 0;
    margin: 0;
}

.com-kiosk-payment__logo {
    flex-shrink: 0;
}

.com-kiosk-payment__label {
    font-weight: 500;
}

/* --- Buttons -------------------------------------------------------------- */

.com-kiosk-submit__button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    white-space: nowrap;
    width: 100%;
    padding: 0.75rem 1.25rem;
    font-size: 1rem;
    font-weight: 600;
    color: var(--kiosk-primary-contrast);
    background: var(--kiosk-primary);
    border: 1px solid var(--kiosk-primary);
    border-radius: var(--kiosk-radius-sm);
    cursor: pointer;
    transition: filter 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
}

.com-kiosk-submit__button:hover {
    filter: brightness(0.92);
    color: var(--kiosk-primary-contrast);
}

.com-kiosk-submit__button:disabled {
    pointer-events: none;
    opacity: 0.5;
}

.com-kiosk-submit__update,
.com-kiosk-account__submit {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    white-space: nowrap;
    padding: 0.5rem 1rem;
    font-size: 0.875rem;
    font-weight: 500;
    color: var(--kiosk-primary);
    background: var(--kiosk-card);
    border: 1px solid var(--kiosk-primary-soft);
    border-radius: var(--kiosk-radius-sm);
    cursor: pointer;
    transition: background-color 0.15s ease-in-out, color 0.15s ease-in-out, border-color 0.15s ease-in-out;
    margin-bottom: 1rem;
}

.com-kiosk-submit__update:hover,
.com-kiosk-account__submit:hover {
    background: var(--kiosk-primary);
    border-color: var(--kiosk-primary);
    color: var(--kiosk-primary-contrast);
}

.com-kiosk-checkout .com-kiosk-checkout__form :focus-visible,
.com-kiosk-account :focus-visible {
    /*
     * A transparent outline, never `outline: none`: the box-shadow ring is
     * the visible focus indicator in normal rendering, but forced-colors
     * mode (Windows High Contrast) drops box-shadows entirely and repaints
     * outlines in a system colour -- a transparent outline becomes visible
     * there, `none` leaves keyboard focus invisible.
     */
    outline: 2px solid transparent;
    outline-offset: 2px;
    border-color: var(--kiosk-primary);
    box-shadow: 0 0 0 3px var(--kiosk-primary-ring);
}

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

.com-kiosk-block--totals {
    background: var(--kiosk-card);
    color: var(--kiosk-muted);
    border: 1px solid var(--kiosk-border);
    border-radius: var(--kiosk-radius);
    padding: 0;
    overflow: hidden;
}

.com-kiosk-totals__heading {
    font-size: 0.9375rem;
    font-weight: 600;
    color: inherit;
    margin: 0;
    padding: 0.875rem 1rem;
    border-bottom: 1px solid var(--kiosk-border);
}

.com-kiosk-block--totals .com-kiosk-totals__lines {
    width: 100%;
    border-collapse: collapse;
    margin: 0;
}

.com-kiosk-block--totals .com-kiosk-totals__lines th,
.com-kiosk-block--totals .com-kiosk-totals__lines td {
    padding: 0.625rem 1rem;
    border-bottom: 1px solid var(--kiosk-border);
    text-align: left;
    background: transparent;
}

.com-kiosk-block--totals .com-kiosk-totals__lines td:last-child,
.com-kiosk-block--totals .com-kiosk-totals__lines th:last-child {
    text-align: right;
}

.com-kiosk-totals__empty {
    margin: 0;
    padding: 0.875rem 1rem;
}

.com-kiosk-totals__grand-total {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    margin: 0;
    padding: 0.875rem 1rem;
    font-weight: 700;
    color: var(--kiosk-primary);
}

.com-kiosk-totals__vat-notice {
    font-size: 0.8125rem;
    color: var(--kiosk-muted);
    margin: 0.5rem 0 1.25rem;
}

/* --- Login box ------------------------------------------------------------ */

.com-kiosk-account {
    background: var(--kiosk-card);
    border: 1px solid var(--kiosk-border);
    border-radius: var(--kiosk-radius);
    padding: 0.875rem 1rem;
    margin-bottom: 1rem;
}

.com-kiosk-account__summary {
    cursor: pointer;
    font-weight: 500;
    color: var(--kiosk-primary);
}

.com-kiosk-account__form {
    margin-top: 0.875rem;
}

.com-kiosk-account__form input[type="text"],
.com-kiosk-account__form input[type="password"] {
    border: 1px solid var(--kiosk-control-border);
    border-radius: var(--kiosk-radius-sm);
    padding: 0.5rem 0.75rem;
}

/* --- Cart toggle ----------------------------------------------------------
 * The shopping-cart button per product tile. JS-only: it ships with
 * [hidden] and checkout.js reveals it; the [hidden] net above keeps it
 * invisible until then. The quantity stepper only shows once the product
 * is in the cart -- driven purely by :has() on the native input, so it
 * also works without JS (and on a browser without :has() the stepper is
 * simply always visible, which loses nothing).
 */
.com-kiosk-offer__cart {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.75rem;
    height: 2.75rem;
    flex-shrink: 0;
    color: var(--kiosk-primary);
    background: var(--kiosk-card);
    border: 1px solid var(--kiosk-primary-soft);
    border-radius: var(--kiosk-radius-sm);
    cursor: pointer;
    transition: background-color 0.15s ease-in-out, color 0.15s ease-in-out, border-color 0.15s ease-in-out;
}

.com-kiosk-offer__cart svg {
    width: 1.5rem;
    height: 1.5rem;
    pointer-events: none;
    flex-shrink: 0;
}

.com-kiosk-offer__cart:hover {
    background: var(--kiosk-primary);
    border-color: var(--kiosk-primary);
    color: var(--kiosk-primary-contrast);
}

.com-kiosk-offer__cart:disabled {
    pointer-events: none;
    opacity: 0.5;
}

/* Which of the two icons shows follows the native input, not a JS state. */
.com-kiosk-offer__cart-remove {
    display: none;
}

.com-kiosk-offer__item:has(> label input:checked) .com-kiosk-offer__cart-add {
    display: none;
}

.com-kiosk-offer__item:has(> label input:checked) .com-kiosk-offer__cart-remove {
    display: block;
}

.com-kiosk-offer__item:has(> label input:checked) .com-kiosk-offer__cart {
    background: var(--kiosk-primary);
    border-color: var(--kiosk-primary);
    color: var(--kiosk-primary-contrast);
}

/* In the cart = stepper visible; not in the cart = nothing to count. The
 * quantity wrapper never carries [hidden] from the condition system, so
 * setting display here cannot fight the native [hidden] handling. */
.com-kiosk-offer__item:not(:has(> label input:checked)) .com-kiosk-offer__quantity {
    display: none;
}

/* Once the cart button took over, the native radio/checkbox disappears --
 * the tile label still toggles the same input for anyone who clicks the
 * text, and the button is the keyboard-reachable control. */
.com-kiosk-offer--enhanced .com-kiosk-offer__item > label > input[type="radio"],
.com-kiosk-offer--enhanced .com-kiosk-offer__item > label > input[type="checkbox"] {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* --- Tile footer -----------------------------------------------------------
 * Stacked: price and stock first, the quantity stepper and cart toggle on
 * their own row below. margin-top: auto pins the whole footer to the
 * bottom of the flex-column tile, so grid tiles of different heights keep
 * their footers aligned.
 */
.com-kiosk-offer__footer {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 0.625rem;
    margin-top: auto;
    padding-top: 0.625rem;
}

.com-kiosk-offer__meta {
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
    min-width: 0;
}

.com-kiosk-offer__stock {
    font-size: 0.8125rem;
    color: var(--kiosk-muted);
}

.com-kiosk-offer__stock-warning {
    font-size: 0.8125rem;
    color: #b3261e;
    margin: 0;
}

.com-kiosk-offer__actions {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

/*
 * Compact customer block. Slightly tighter type and spacing on the customer
 * details form, in every skin: the block holds many short fields, so the
 * default rhythm reads unnecessarily airy there.
 */
.com-kiosk-block--customer .com-kiosk-field {
    margin-bottom: 0.75rem;
}

.com-kiosk-block--customer .com-kiosk-field label {
    font-size: 0.9em;
}

.com-kiosk-block--customer input:not([type="checkbox"]):not([type="radio"]),
.com-kiosk-block--customer select,
.com-kiosk-block--customer textarea {
    font-size: 0.9rem;
    padding-top: 0.375rem;
    padding-bottom: 0.375rem;
}

/*
 * The customer block's field rows. Every field carries its configured width
 * as a `--w-{25,50,75,100}` class; the sections are flex rows that wrap, so
 * the widths compose into rows naturally (50+25+25 = street + house number +
 * addition on one row). That per-field width IS the layout control -- there
 * is no separate "columns" switch, because a field set to 100 already spans
 * the row on its own and the seeded defaults are all 100 unless the admin
 * says otherwise.
 *
 * `flex-grow` is proportional to the width, which is what keeps the layout
 * flexible: hide the addition and the street/house-number pair stretches in
 * proportion to fill the row; hide the last name and the first name takes
 * the full width. A `[hidden]` wrapper leaves the flow entirely, so the
 * JS visibility toggle never has to know about widths. Below the 48rem
 * tier everything stacks, matching the offer and payment grids' breakpoint.
 */
@media (min-width: 48rem) {
    /*
     * Section fieldsets only. A radio or checkbox field renders its options
     * inside a `fieldset.com-kiosk-field__group` of its own, and that one
     * must stay a plain block: its children are options, not fields, so
     * they carry no width class and would end up sitting beside each other.
     */
    .com-kiosk-block--customer fieldset:not(.com-kiosk-field__group) {
        display: flex;
        flex-wrap: wrap;
        column-gap: 1rem;
        align-items: flex-start;
    }

    .com-kiosk-block--customer fieldset > legend,
    .com-kiosk-block--customer fieldset > fieldset,
    .com-kiosk-block--customer fieldset > p,
    .com-kiosk-block--customer fieldset > div:not(.com-kiosk-field) {
        flex-basis: 100%;
    }

    .com-kiosk-block--customer .com-kiosk-field {
        flex: 4 1 100%;
        min-width: 0;
    }

    .com-kiosk-block--customer .com-kiosk-field--w-25 {
        flex: 1 1 calc(25% - 0.75rem);
    }

    .com-kiosk-block--customer .com-kiosk-field--w-50 {
        flex: 2 1 calc(50% - 0.5rem);
    }

    .com-kiosk-block--customer .com-kiosk-field--w-75 {
        flex: 3 1 calc(75% - 0.25rem);
    }
}

/*
 * Single checkboxes (terms, switches, the create-account box): the label
 * sits NEXT TO the box, never above it. A framework's own block-level label
 * rule would otherwise push it onto its own line.
 *
 * The `label` element qualifier is load-bearing, not decoration. The label
 * carries both this class and the active framework's label class, and
 * `.uk-form-label { display: block }` (UIkit, and the same shape in other
 * frameworks) has identical specificity to a bare
 * `.com-kiosk-field__check-label`. A site stylesheet is free to load after
 * this one -- a YOOtheme theme.css does exactly that -- so a same-specificity
 * rule loses purely on source order and the label drops below the box.
 * Adding the element qualifier puts this rule above any single-class
 * framework rule regardless of load order.
 */
.com-kiosk-checkout label.com-kiosk-field__check-label,
label.com-kiosk-field__check-label {
    display: inline;
    margin-bottom: 0;
}

/*
 * The gap between box and label. Bootstrap's own `.form-check` wrapper
 * already reserves it through its padding, so only the wrapper-less skins
 * (UIkit, plain, none) need it here.
 */
.com-kiosk-checkout :not(.form-check) > label.com-kiosk-field__check-label,
:not(.form-check) > label.com-kiosk-field__check-label {
    margin-left: 0.375rem;
}

/*
 * The create-account password only exists while the box is ticked. CSS
 * `:has()` keeps this working without JS; the controller enforces the
 * password server-side either way. This is the one deliberate exception to
 * Guard A (no `display` on `.com-kiosk-field`): this wrapper carries no
 * `data-kiosk-condition`, so the JS visibility engine never touches it.
 */
.com-kiosk-account-create__password {
    display: none;
}

.com-kiosk-account-create:has(#kiosk-create-account:checked) .com-kiosk-account-create__password {
    display: block;
}

/*
 * The discount block's input-plus-button row. The block renders with the
 * active framework's card/input/button classes (see DiscountBlock::render()),
 * but no framework supplies "input and button side by side, input grows":
 * that layout choice is this stylesheet's job in every mode, none included.
 */
.com-kiosk-discount__row {
    display: flex;
    align-items: stretch;
    gap: 0.5rem;
    margin-top: 0.375rem;
}

.com-kiosk-discount__row .com-kiosk-discount__input {
    flex: 1 1 auto;
    min-width: 0;
}

.com-kiosk-discount__row .com-kiosk-discount__button {
    flex: 0 0 auto;
    white-space: nowrap;
}

/*
 * The order bump block's own bits: the image never overflows its card, and
 * the checkbox label reads as one clickable line. Card, checkbox and title
 * classes come from the active framework (see OrderbumpBlock::render()).
 */
.com-kiosk-orderbump__image {
    max-width: 100%;
    height: auto;
    margin-bottom: 0.5rem;
}

label.com-kiosk-orderbump__label {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    cursor: pointer;
}

/*
 * The guarantee block: up to five marks over short promises, side by side.
 * The icon takes the template's own text colour, because it is drawn in
 * `currentColor` rather than shipped as an image, and both marks sit on
 * their own line so the title below them starts flush left.
 */
.com-kiosk-guarantee__heading {
    margin-bottom: 0.75rem;
}

.com-kiosk-guarantee__icon,
.com-kiosk-guarantee__image {
    display: block;
    margin-bottom: 0.5rem;
}

.com-kiosk-guarantee__image {
    max-width: 100%;
    height: auto;
}

.com-kiosk-guarantee__card {
    height: 100%;
}

.com-kiosk-guarantee__title {
    margin-bottom: 0.25rem;
}

.com-kiosk-guarantee__text > :last-child {
    margin-bottom: 0;
}

/*
 * The testimonials block: three quote cards. The grid classes come from the
 * active framework, so what is left here is the inside of a card -- and, in
 * the none mode, a grid of its own, because a block that falls back to a
 * single column of three quotes pushes the order button off the screen.
 */
.com-kiosk-testimonials__heading {
    margin-bottom: 0.75rem;
}


.com-kiosk-testimonials__card {
    height: 100%;
    margin: 0;
}

.com-kiosk-testimonials__quote {
    margin: 0 0 0.5rem;
    font-style: italic;
}

.com-kiosk-testimonials__by {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.375rem;
}

.com-kiosk-testimonials__photo {
    width: 2rem;
    height: 2rem;
    border-radius: 50%;
    object-fit: cover;
}

.com-kiosk-testimonials__name {
    font-weight: 600;
}

.com-kiosk-testimonials__rating {
    margin-bottom: 0.375rem;
    line-height: 1;
}

/*
 * A star is drawn once and filled twice: unfilled it is an outline in the
 * text colour at low opacity, filled it is solid. One shape, two states, no
 * second path to keep in step with the first.
 */
.com-kiosk-testimonials__star {
    fill: none;
    stroke: currentColor;
    stroke-width: 1.5;
    stroke-linejoin: round;
    opacity: 0.35;
}

.com-kiosk-testimonials__star--on {
    fill: currentColor;
    opacity: 1;
}

/*
 * The countdown block: the clock reads as a row of numbers with their units
 * under them. Tabular figures keep the digits from jumping sideways as the
 * seconds tick over, which is the whole difference between a clock and a
 * flicker.
 */
.com-kiosk-countdown__clock {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    margin: 0.5rem 0;
}

.com-kiosk-countdown__part {
    display: flex;
    flex-direction: column;
    align-items: center;
    min-width: 2.5rem;
}

.com-kiosk-countdown__value {
    font-size: 1.5rem;
    font-weight: 600;
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum";
}

.com-kiosk-countdown__unit {
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    opacity: 0.7;
}

.com-kiosk-countdown__text > :last-child,
.com-kiosk-countdown__expired > :last-child {
    margin-bottom: 0;
}

/*
 * The none mode's own grid for the two blocks that size themselves to what
 * an administrator filled in.
 *
 * Bootstrap and UIkit get their widths from $ui->gridItem(), which the block
 * calls with the column count. Without a framework there is no class that
 * says "a fifth", so the block writes the number onto the list as a `--N`
 * modifier -- the same trick the offer block's `--grid-N` uses -- and these
 * rules read it back.
 *
 * The `:not()` guards keep these rules off a page that does have a
 * framework, where the row and column classes already do the work and a
 * second grid on top of them would fight it.
 */
.com-kiosk-guarantee__list:not([class*="row"]):not([class*="uk-grid"]),
.com-kiosk-testimonials__list:not([class*="row"]):not([class*="uk-grid"]) {
    display: grid;
    gap: 1rem;
    grid-template-columns: repeat(1, minmax(0, 1fr));
}

@media (min-width: 48em) {
    .com-kiosk-guarantee__list--2:not([class*="row"]):not([class*="uk-grid"]),
    .com-kiosk-testimonials__list--2:not([class*="row"]):not([class*="uk-grid"]) {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .com-kiosk-guarantee__list--3:not([class*="row"]):not([class*="uk-grid"]),
    .com-kiosk-testimonials__list--3:not([class*="row"]):not([class*="uk-grid"]) {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }

    .com-kiosk-guarantee__list--4:not([class*="row"]):not([class*="uk-grid"]) {
        grid-template-columns: repeat(4, minmax(0, 1fr));
    }

    .com-kiosk-guarantee__list--5:not([class*="row"]):not([class*="uk-grid"]) {
        grid-template-columns: repeat(5, minmax(0, 1fr));
    }
}
