/* =========================================================================
   Flux Hosted Fields — checkout + modal

   House style, lifted from the Flux payment link
   (one_time_payment_link/src/app/payment-link/styles/_variables.scss,
   _forms.scss, _layout-cards.scss) and from the reference integration at
   hosted_fields/example/index.html. Tokens and the 90% type/space scales are
   copied verbatim rather than re-derived — most of the compaction is simply
   refusing to use 16/24/32px.

   Two things differ from the reference, on purpose:

   1. BRAND COLOUR IS THE MERCHANT'S. The plugin injects --flux-accent,
      --flux-accent-ring and --flux-btn-bg on :root from the gateway settings
      (see flux_enqueue_frontend_assets). Those win; the house #635bff is only
      the fallback. Everything that is NOT an expression of merchant brand —
      neutrals, field chrome, type, spacing — is house-verbatim.

   2. NO PAGE SHELL. This form renders inside a merchant's theme, so every
      rule here is scoped to the plugin's own .flux-hf-* namespace and to its
      two containers (.flux-hosted-fields-form, .flux-hf-modal). Bare element
      selectors are always qualified by one of ours. Specificity is kept low
      and !important is not used — a tighter selector does the job.

   MARKUP NOTE: .flux-hf-group / .flux-hf-group--address are inserted at
   runtime by flux-hosted-checkout.js (groupRows). The PHP emits one
   .flux-hf-row per field; the house style is one bordered block per SECTION.
   Every rule below also has a sane ungrouped fallback, so if that JS never
   runs the form still reads as a form.
   ========================================================================= */

.flux-hosted-fields-form,
.flux-hf-modal {
    /* Brand — merchant setting wins, house colour is the fallback */
    --fx-brand: var(--flux-accent, #635bff);
    --fx-brand-ring: var(--flux-accent-ring, rgba(99, 91, 255, 0.08));
    --fx-cta: var(--flux-btn-bg, #635bff);

    /* Neutrals */
    --fx-gray-50: #fafafa;
    --fx-gray-100: #f5f5f5;
    --fx-gray-200: #e5e5e5;
    --fx-gray-600: #666;
    --fx-gray-900: #1a1a1a;

    /* Field chrome */
    --fx-field-border: #e0e0e0;
    --fx-field-border-hover: #c4c4c4;
    --fx-divider: #e6ebf1;
    --fx-rule: #ebebeb;
    --fx-ink: #30313d;
    --fx-ink-muted: #6d6e78;
    --fx-danger: #df1b41;
    --fx-danger-tint: rgba(223, 27, 65, 0.045);
    --fx-danger-border: #dc2626;
    --fx-positive: #1b7a3d;

    /* Type scale, 90% — the same scale as the source, expressed in px rather
       than rem ON PURPOSE. The reference page owns its own <html>; this form
       does not, and a theme with `html { font-size: 62.5% }` (a very common
       10px-root pattern) would shrink every rem here by 37% while the iframe
       inputs, whose size is set in px through the SDK, stayed put. */
    --fx-text-sm: 10.8px;   /* 0.675rem */
    --fx-text-md: 12.6px;   /* 0.788rem */
    --fx-text-base: 13.5px; /* 0.844rem */
    --fx-text-lg: 14.4px;   /* 0.9rem   */

    /* Spacing scale, 90% */
    --fx-space-xs: 4px;
    --fx-space-sm: 7px;
    --fx-space-md: 11px;
    --fx-space-lg: 14px;
    --fx-space-xl: 18px;
    --fx-space-2xl: 22px;

    --fx-font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif;
}

.flux-hosted-fields-form {
    font-family: var(--fx-font);
    -webkit-font-smoothing: antialiased;
    /* flux-checkout.css zeroes .payment_box padding, so the form would sit
       flush against the gateway label on a multi-gateway store. Take the gap
       on our own container rather than reinstating padding on theirs. */
    margin: var(--fx-space-sm) 0 0;
}

.flux-hosted-fields-form *,
.flux-hf-modal * {
    box-sizing: border-box;
}

/* =========================================================================
   THEME-PRESSURE ESCALATION  (read before "tidying" the doubled id away)

   This form renders inside `#payment ul.payment_methods li.wc_payment_method
   div.payment_box`. ANY theme rule that mentions #payment carries an id, so it
   beats every plain-class rule in this file outright — and the rules a
   WooCommerce theme is most likely to write are exactly ours:
   `#payment label`, `#payment .payment_box div`, and so on. Namespacing alone
   does nothing about that; it prevents collisions, not defeats.

   So the four highest-risk families below — the micro-label, the field
   container (its 28px height IS the compaction), the inline error and its
   :empty collapse, and the section title — each carry a second selector with
   the form's own id repeated twice, i.e. (2,x,y). TWO ids beat any single-id
   theme rule whatever its class count; `#flux-hosted-fields-form label` alone
   would be (1,0,1) and would LOSE to a routine
   `.woocommerce-checkout #payment ul.payment_methods li label` at (1,4,1).
   The doubled id is self-contained — it depends on no theme or core markup,
   unlike `#payment #flux-hosted-fields-form`, which would style nothing at all
   on a page that does not render `#payment`.

   RULES:
   - The plain-class selector STAYS on every one of them. It is what styles the
     MODAL (rendered at wp_footer, outside #payment, where class specificity is
     enough) and it is the rule anyone reading this file is meant to see first.
   - Escalate a WHOLE family or none of it. Raising a base rule while leaving
     its `:empty` / `:first-child` / `.flux-hf-cell-invalid` variant behind
     inverts their order and deletes the variant.
   - Still no !important anywhere. A merchant theme that fights past two ids
     needs three, or a snippet — not an unanswerable declaration.
   - LIMIT, stated honestly: a theme rule carrying TWO ids
     (`#content #payment ... label`) still wins. Nothing short of !important
     answers that, and it has not been worth it.
   ========================================================================= */

/* =========================================================================
   Section heading
   ========================================================================= */

.flux-hf-section-title,
#flux-hosted-fields-form#flux-hosted-fields-form .flux-hf-section-title {
    font-family: var(--fx-font);
    font-size: 11px;
    font-weight: 600;
    line-height: 1.4;
    color: var(--fx-ink);
    letter-spacing: -0.01em;
    text-transform: none;
    margin: var(--fx-space-xl) 0 var(--fx-space-sm);
    padding-top: var(--fx-space-lg);
    border-top: 1px solid var(--fx-rule);
}

.flux-hf-section-title:first-child,
#flux-hosted-fields-form#flux-hosted-fields-form .flux-hf-section-title:first-child {
    margin-top: 0;
    padding-top: 0;
    border-top: 0;
}

/* =========================================================================
   THE GROUPED FIELD BLOCK — the signature component.
   One bordered box per logical section; rows inside it are separated by a
   hairline, not by whitespace.
   ========================================================================= */

.flux-hf-group {
    border: 1px solid var(--fx-field-border);
    border-radius: 8px;
    background: #fff;
    overflow: hidden;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.flux-hf-group + .flux-hf-group {
    margin-top: var(--fx-space-sm);
}

.flux-hf-group:hover:not(.flux-hf-group-focused):not(:focus-within) {
    border-color: var(--fx-field-border-hover);
}

/* Focus ring. Kept as TWO rules on purpose: if one selector is unsupported it
   must not invalidate the other by being comma-joined to it.

   .flux-hf-group-focused is the primary signal — the JS sets it from the SDK's
   own .focused class, because :focus-within is not dependable across a
   cross-origin iframe boundary and :has() is a hard support cliff (an engine
   without it drops the whole rule, and a payment field that stops showing
   focus is not an acceptable degradation). :focus-within stays for any native
   control that ends up inside a group. */
.flux-hf-group.flux-hf-group-focused {
    border-color: var(--fx-brand);
    box-shadow: 0 0 0 3px var(--fx-brand-ring);
}

.flux-hf-group:focus-within {
    border-color: var(--fx-brand);
    box-shadow: 0 0 0 3px var(--fx-brand-ring);
}

/* Rows inside a group carry no chrome of their own — the box owns it — and
   need no reset to say so: the ungrouped fallback below is a CHILD selector on
   the form / modal body, so it cannot match a row that groupRows() has moved
   inside a .flux-hf-group. Do NOT "tidy" this up by adding a
   `.flux-hf-group .flux-hf-row { background: transparent }` reset: at (0,2,0)
   it outranks .flux-hf-cell-invalid (0,1,0) and silently deletes the invalid
   tint, which is the one visual state on this form that has to work. */

.flux-hf-group > .flux-hf-row + .flux-hf-row,
.flux-hf-group > .flux-hf-row + .flux-hf-row-split,
.flux-hf-group > .flux-hf-row-split + .flux-hf-row,
.flux-hf-group > .flux-hf-row-split + .flux-hf-row-split {
    border-top: 1px solid var(--fx-divider);
}

/* Ungrouped fallback: if groupRows() never ran, each row is its own box. */
.flux-hosted-fields-form > .flux-hf-row,
.flux-hosted-fields-form > .flux-hf-row-split,
.flux-hf-modal-body > .flux-hf-row,
.flux-hf-modal-body > .flux-hf-row-split {
    border: 1px solid var(--fx-field-border);
    border-radius: 8px;
    background: #fff;
    margin-bottom: var(--fx-space-sm);
}

/* =========================================================================
   Cells — every field is label-over-input INSIDE the box
   ========================================================================= */

.flux-hf-row-split {
    display: flex;
}

.flux-hf-row-split > .flux-hf-field {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.flux-hf-row-split > .flux-hf-field + .flux-hf-field {
    border-left: 1px solid var(--fx-divider);
}

/* A non-split row IS its own cell. */
.flux-hf-row {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.flux-hosted-fields-form label,
#flux-hosted-fields-form#flux-hosted-fields-form label,
.flux-hf-modal-body label {
    display: block;
    font-family: var(--fx-font);
    font-size: 9px;
    font-weight: 600;
    line-height: 1.3;
    color: var(--fx-ink-muted);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    margin: 0;
    padding: 5px 10px 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* NO `color` here on purpose. This word is the ONLY cue telling the customer
   which field may be left blank, so it is instruction, not decoration. The
   reference page hit the same trap and took the same fix: #a3aab4 on white is
   2.34:1, about half the 4.5:1 AA threshold. Inheriting the label's own
   --fx-ink-muted gives 5.06:1 and changes nothing else about the hierarchy —
   the weight and letter-spacing below are what set the word apart, and the
   PHP already wraps it in parentheses. Do not "restore" a lighter grey. */
.flux-hf-optional {
    font-weight: 500;
    letter-spacing: 0.03em;
    text-transform: none;
}

/* The iframe container. Style this — never the input inside it; that lives in
   another origin and is reachable only through the SDK's create() style
   options (fontSize, fontFamily, color, placeholderColor). */
.flux-hf-field-container,
#flux-hosted-fields-form#flux-hosted-fields-form .flux-hf-field-container {
    position: relative;
    height: 28px;
    min-height: 28px;
    padding: 0 10px 5px;
    margin: 0;
    border: 0;
    border-radius: 0;
    background: transparent;
    cursor: text;
    overflow: hidden;
}

.flux-hf-field-container iframe,
#flux-hosted-fields-form#flux-hosted-fields-form .flux-hf-field-container iframe {
    display: block;
    width: 100%;
    height: 100%;
    border: 0;
}

/* Valid is SILENT. The affirmation is the enabled pay button, not a green
   outline on every field. (.valid is still set by the JS for other consumers.) */
.flux-hf-field-container.valid,
.flux-hf-field-container.focused,
#flux-hosted-fields-form#flux-hosted-fields-form .flux-hf-field-container.valid,
#flux-hosted-fields-form#flux-hosted-fields-form .flux-hf-field-container.focused {
    background: transparent;
}

/* Invalid: tint the offending CELL, redden its label, outline the whole box.
   Both classes are set by the JS (updateFieldUI / refreshGroupState) so this
   works on every engine. Focus outranks invalid — the :not() below — so the
   red clears the moment the customer types. */
.flux-hf-cell-invalid {
    background: var(--fx-danger-tint);
}

/* ...and again, higher, for the UNGROUPED fallback. That layout gives every
   row its own box with `background: #fff` at (0,2,0), which outranks the
   (0,1,0) tint above — so an invalid non-split row silently lost its tint
   whenever groupRows() had not run. This is the exact trap the note further up
   warns about, in this file's own fallback. (0,3,0), so it wins outright
   rather than on source order. Split rows are unaffected: there the class
   lands on the inner .flux-hf-field, which the fallback never matches. */
.flux-hosted-fields-form > .flux-hf-row.flux-hf-cell-invalid,
.flux-hf-modal-body > .flux-hf-row.flux-hf-cell-invalid {
    background: var(--fx-danger-tint);
}

.flux-hf-cell-invalid > label,
#flux-hosted-fields-form#flux-hosted-fields-form .flux-hf-cell-invalid > label {
    color: #b91c1c;
}

.flux-hf-group.flux-hf-group-invalid:not(.flux-hf-group-focused):not(:focus-within) {
    border-color: var(--fx-danger-border);
    box-shadow: 0 0 0 3px rgba(220, 38, 38, 0.08);
}

/* =========================================================================
   Inline field error — lives inside the cell, under the input, and COLLAPSES
   when empty. A fixed error slot costs ~16px per field for nothing.
   ========================================================================= */

.flux-hf-error,
#flux-hosted-fields-form#flux-hosted-fields-form .flux-hf-error {
    display: flex;
    align-items: flex-start;
    gap: 6px;
    padding: 0 10px 6px;
    margin: 0;
    min-height: 0;
    font-family: var(--fx-font);
    font-size: 11.5px;
    font-weight: 500;
    line-height: 1.4;
    color: var(--fx-danger);
}

.flux-hf-error:empty,
#flux-hosted-fields-form#flux-hosted-fields-form .flux-hf-error:empty {
    display: none;
}

.flux-hf-error::before,
#flux-hosted-fields-form#flux-hosted-fields-form .flux-hf-error::before {
    content: '!';
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 13px;
    height: 13px;
    margin-top: 1px;
    border-radius: 50%;
    background: rgba(223, 27, 65, 0.12);
    color: var(--fx-danger);
    font-size: 9px;
    font-weight: 700;
    line-height: 1;
}

/* =========================================================================
   Address autocomplete
   A block that must let a popover escape needs its own single-cell box with
   overflow:visible — the grouped block clips its children to get its corners.
   ========================================================================= */

.flux-hf-group--address {
    overflow: visible;
    position: relative;
}

.flux-hf-group--address > .flux-hf-row {
    border-radius: 7px;
}

.flux-hf-address-wrapper {
    position: relative;
}

.flux-hf-suggestions-dropdown {
    position: absolute;
    top: calc(100% + 4px);
    left: -1px;
    right: -1px;
    z-index: 10000;
    display: none;
    max-height: 232px;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: var(--fx-space-xs) 0;
    background: #fff;
    border: 1px solid #e3e6eb;
    border-radius: 8px;
    box-shadow: 0 12px 32px rgba(15, 23, 42, 0.12),
                0 2px 4px rgba(15, 23, 42, 0.04);
}

.flux-hf-suggestions-dropdown.visible {
    display: block;
}

.flux-hf-suggestion-item {
    padding: var(--fx-space-sm) var(--fx-space-md);
    cursor: pointer;
    user-select: none;
    border: 0;
    transition: background 0.1s ease;
}

.flux-hf-suggestion-item:hover,
.flux-hf-suggestion-item.active {
    background: #f3f5f8;
}

.flux-hf-suggestion-item:active {
    background: #e8ecf1;
}

.flux-hf-suggestion-main {
    font-family: var(--fx-font);
    font-size: var(--fx-text-md);
    font-weight: 500;
    line-height: 1.3;
    color: #1a1f36;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.flux-hf-suggestion-secondary {
    font-family: var(--fx-font);
    font-size: var(--fx-text-sm);
    line-height: 1.3;
    color: #6b7280;
    margin-top: 1px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* =========================================================================
   Authorization status + messages

   Status colour never fills a large area: a neutral surface with a 2px left
   rule, and the tone lives in the rule and the text — never in the fill.
   Never two status hues at once.
   ========================================================================= */

.flux-hf-auth-status {
    display: flex;
    align-items: center;
    gap: 9px;
    margin-top: var(--fx-space-md);
    padding: 8px var(--fx-space-md);
    border: 1px solid var(--fx-gray-200);
    border-radius: 7px;
    background: var(--fx-gray-50);
    font-family: var(--fx-font);
    font-size: var(--fx-text-md);
    line-height: 1.45;
    color: var(--fx-ink);
}

/* Spinners and small icons carry the brand; large surfaces never do. */
.flux-hf-spinner {
    width: 14px;
    height: 14px;
    flex-shrink: 0;
    border: 2px solid #dfe3ea;
    border-top-color: var(--fx-brand);
    border-radius: 50%;
    animation: flux-hf-spin 0.8s linear infinite;
}

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

.flux-hf-error-msg {
    position: relative;
    margin-top: var(--fx-space-md);
    padding: var(--fx-space-sm) var(--fx-space-md) var(--fx-space-sm) var(--fx-space-lg);
    border: 1px solid var(--fx-gray-200);
    border-radius: 8px;
    background: var(--fx-gray-50);
    font-family: var(--fx-font);
    font-size: var(--fx-text-md);
    font-weight: 500;
    line-height: 1.45;
    color: var(--fx-gray-900);
    overflow: hidden;
}

.flux-hf-error-msg::before {
    content: '';
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 2px;
    background: #c9ced6;
}

.flux-hf-error-msg.flux-hf-msg--error {
    color: var(--fx-danger);
}

.flux-hf-error-msg.flux-hf-msg--error::before {
    background: var(--fx-danger);
}

.flux-hf-error-msg.flux-hf-msg--ok {
    color: var(--fx-positive);
}

.flux-hf-error-msg.flux-hf-msg--ok::before {
    background: var(--fx-positive);
}

/* --notice is deliberately neutral: "we'll confirm your card when you place
   the order" is information, not a status. */
.flux-hf-error-msg.flux-hf-msg--notice {
    color: var(--fx-gray-600);
}

/* =========================================================================
   Modal (cart / mini-cart)
   ========================================================================= */

.flux-hf-modal-overlay {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 99999;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--fx-space-xl, 18px);
    background: rgba(17, 20, 28, 0.45);
}

.flux-hf-modal {
    width: 100%;
    max-width: 440px;
    max-height: 90vh;
    overflow-y: auto;
    background: #fff;
    border-radius: 12px;
    font-family: var(--fx-font);
    -webkit-font-smoothing: antialiased;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08),
                0 24px 64px rgba(15, 23, 42, 0.18);
}

.flux-hf-modal-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: var(--fx-space-md) var(--fx-space-xl);
    border-bottom: 1px solid var(--fx-rule);
}

.flux-hf-modal-title {
    font-family: var(--fx-font);
    font-size: var(--fx-text-lg);
    font-weight: 600;
    letter-spacing: -0.01em;
    color: var(--fx-gray-900);
}

.flux-hf-modal-close {
    background: none;
    border: 0;
    box-shadow: none;
    font-size: 20px;
    line-height: 1;
    padding: 0 2px;
    cursor: pointer;
    color: #a3aab4;
    transition: color 0.15s ease;
}

.flux-hf-modal-close:hover {
    color: var(--fx-gray-900);
    background: none;
}

.flux-hf-modal-body {
    padding: var(--fx-space-xl);
}

.flux-hf-modal-footer {
    padding: var(--fx-space-md) var(--fx-space-xl) var(--fx-space-xl);
}

/* Primary CTA. Elevation belongs to the primary alone — nothing else in this
   stylesheet gets a shadow. */
.flux-hf-modal-pay-btn {
    width: 100%;
    min-height: 48px;
    padding: 0 var(--fx-space-lg);
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--fx-space-sm);
    font-family: var(--fx-font);
    font-size: 14px;
    font-weight: 600;
    letter-spacing: 0.01em;
    color: #fff;
    background: var(--fx-cta);
    border: 0;
    border-radius: 8px;
    cursor: pointer;
    transition: background 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08),
                0 2px 8px rgba(0, 0, 0, 0.04);
}

.flux-hf-modal-pay-btn:hover:not(:disabled) {
    background: color-mix(in srgb, var(--fx-cta) 88%, #000);
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.12),
                0 4px 16px rgba(0, 0, 0, 0.08);
    transform: translateY(-1px);
}

.flux-hf-modal-pay-btn:active:not(:disabled) {
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
    transform: translateY(0);
}

.flux-hf-modal-pay-btn:focus-visible {
    outline: none;
    box-shadow: 0 0 0 2px #fff, 0 0 0 4px var(--fx-cta);
}

.flux-hf-modal-pay-btn:disabled {
    opacity: 0.45;
    cursor: not-allowed;
    box-shadow: none;
    transform: none;
}

/* =========================================================================
   Responsive

   Split rows stay side by side on small screens on purpose — expiry/CVV and
   city/state read better paired than stacked, and the cells are still ~150px
   wide at 360px. The old rule broke them into a column and cost a screenful.
   ========================================================================= */

@media (max-width: 380px) {
    .flux-hf-row-split {
        display: block;
    }

    .flux-hf-row-split > .flux-hf-field + .flux-hf-field {
        border-left: 0;
        border-top: 1px solid var(--fx-divider);
    }
}

@media (max-width: 480px) {
    .flux-hf-modal-overlay {
        padding: 0;
        align-items: flex-end;
    }

    .flux-hf-modal {
        max-width: 100%;
        max-height: 94vh;
        border-radius: 12px 12px 0 0;
    }
}
