/**
 * Button — size presets and the disabled / loading states.
 *
 * Declared from Ractro_Widget_Button::get_style_depends(), so it loads on a page
 * only when a Button is on it, and the editor inlines it into the canvas shadow
 * root automatically (Ractro_Widget_Manager::get_widgets_css) — which is what
 * makes the presets and the spinner render identically on both surfaces.
 *
 * NOTHING HERE PAINTS ON A DEFAULT BUTTON. The preset block below defines custom
 * properties and no properties; the state blocks are all gated behind a class
 * that render() emits only when the matching switch is on. A Button with no
 * preset and no state is byte-identical markup and pixel-identical output to
 * before this file existed.
 *
 * WHY THE PRESETS ARE CUSTOM PROPERTIES AND NOT A `.is-size-lg` RULE.
 * The obvious shape — `.ractro-button-link.is-size-lg { font-size: 20px }` — is
 * dead on arrival in this engine, and measurably so. `btn_font_size` carries a
 * schema default of 16 (controls/typography.php), and an UNTOUCHED control still
 * compiles: every Button on every page emits
 *
 *     .ractro-element-<id> .ractro-button-link { … font-size: 16px; … }
 *
 * from the DEFAULTS pass. That rule is specificity (0,2,0) — the same as a
 * two-class selector here — and it is printed at wp_head priority 999, i.e.
 * AFTER every enqueued stylesheet including this one. So a class rule in this
 * file loses the tie on source order, and a size preset would move the padding
 * (default '', emits nothing) while the font-size sat at 16px forever: a control
 * that half works, which is worse than one that does not exist.
 *
 * Compiling the preset through the control pipeline instead puts it in the same
 * cascade layer as the controls it must negotiate with, where the ordering rules
 * are explicit and linted. See the btn_size comment in widgets/button.php.
 */

/* ---------------------------------------------------------------- SIZE PRESETS
 *
 * The pairs, and only the pairs. `btn_size` compiles
 * `padding: var(--rbtn-pad-{{VALUE}}); font-size: var(--rbtn-fs-{{VALUE}});`
 * onto the element, so these names are the contract between that control's
 * option values (sm|md|lg) and this file.
 *
 * MEDIUM IS TODAY'S BUTTON, exactly: assets/ractro-base.css sets
 * `padding: 12px 26px` and the typography default is 16px. That is deliberate —
 * "Medium" must be the size the author already has, or picking the middle option
 * of three would visibly move a button that was already correct. Small and Large
 * then step away from a real anchor rather than from an invented one.
 *
 * Padding and font-size move TOGETHER, which is the whole point of the control:
 * the ratio of horizontal padding to text size stays near 1.6 and vertical near
 * 0.6 across all three, so a Large button reads as the same button scaled and
 * not as a different one. That coherent pair is what "make it bigger" used to
 * cost two edits and a guess.
 *
 * Defined on the LINK, not on :root or :host. The canvas renders inside a shadow
 * root, where a `:root` declaration does not reach these nodes at all — the
 * presets would resolve to nothing in the editor and correctly on the front end,
 * which is the editor/live parity failure this project keeps paying for.
 */
.ractro-button-link {
    /* VARIANTS. btn_variant emits background/color/border/box-shadow as
       var(--rbtn-*-<variant>), so one control moves six properties and an
       explicit Style control declared later still wins its own.

       Every variant is defined for all six vars — a var with no value at all
       makes the whole declaration invalid at computed-value time and would drop
       the property silently, which is the failure mode this file keeps avoiding.
       `revert` is used where a variant wants the stylesheet's own base value
       back rather than a literal, so the base rule stays the single source of
       the solid look.

       Colours come from the global tokens with literal fallbacks, so an outline
       button follows the site palette but never vanishes if tokens are absent. */
    --rbtn-bg-outline: transparent;
    --rbtn-fg-outline: var(--ractro-color-primary, #4f46e5);
    --rbtn-bd-outline: var(--ractro-color-primary, #4f46e5);
    --rbtn-bs-outline: solid;
    --rbtn-bw-outline: 2px;
    --rbtn-sh-outline: none;

    --rbtn-bg-ghost: color-mix(in srgb, var(--ractro-color-primary, #4f46e5) 12%, transparent);
    --rbtn-fg-ghost: var(--ractro-color-primary, #4f46e5);
    --rbtn-bd-ghost: transparent;
    --rbtn-bs-ghost: solid;
    --rbtn-bw-ghost: 0;
    --rbtn-sh-ghost: none;

    /* A link variant is text, so it drops the box entirely — no padding reset
       here though: padding stays the author's, because a link button in a row of
       buttons usually still wants to line up with them. */
    --rbtn-bg-link: transparent;
    --rbtn-fg-link: var(--ractro-color-primary, #4f46e5);
    --rbtn-bd-link: transparent;
    --rbtn-bs-link: none;
    --rbtn-bw-link: 0;
    --rbtn-sh-link: none;

    --rbtn-pad-sm: 8px 18px;
    --rbtn-fs-sm: 14px;

    --rbtn-pad-md: 12px 26px;
    --rbtn-fs-md: 16px;

    --rbtn-pad-lg: 17px 36px;
    --rbtn-fs-lg: 20px;
}

/* ------------------------------------------------------------ DISABLED STATE
 *
 * The class is COSMETIC ONLY. What actually makes the button non-interactive is
 * in render(): the `href` attribute is not emitted at all. An <a> without an
 * href is not a link — it is not focusable, it is not in the tab order, Enter
 * does nothing to it and a click does nothing to it. That is the mechanism.
 *
 * `pointer-events: none` is deliberately NOT used here, and not merely because
 * it is insufficient. It is insufficient — it blocks the mouse and leaves a
 * focusable link that Enter still follows, so a keyboard user sails straight
 * through a button the design says is disabled. But adding it on top of the
 * missing href would also swallow `cursor: not-allowed`, since a box that
 * receives no pointer events shows no cursor of its own. With the href gone
 * there is nothing left to block, so the honest cursor is affordable and the
 * hover affordances below are what stop the button looking live.
 */
.ractro-button-link.is-disabled {
    /* Overridable: btn_disabled_opacity compiles `opacity` onto
       `.ractro-element-<id> .ractro-button-link`, which is the same specificity
       printed later, so an author value wins this cleanly and without
       !important. Unset, it emits nothing and this is what shows. */
    opacity: 0.55;
    cursor: not-allowed;
    /* The one thing users read as "this is off": text selection and the hover
       lift both say "interactive". */
    user-select: none;
    -webkit-user-select: none;
}

/* Base CSS gives every button a hover lift and an active press. Both must stop,
   or a button that cannot be activated still animates as though it can. */
.ractro-button-link.is-disabled:hover,
.ractro-button-link.is-disabled:active {
    transform: none;
    box-shadow: none;
}

/* ------------------------------------------------------------- LOADING STATE
 *
 * A loading button is busy, not merely decorated, so render() treats it exactly
 * like the disabled one — no href — and adds `aria-busy="true"`. A "loading"
 * button that still navigates on the second click is a double-submit waiting to
 * happen, and there is no JS on this element to guard against one: the plugin
 * ships none for static widgets, which is also why the spinner below is pure
 * CSS and not a script.
 */
.ractro-button-link.is-loading {
    cursor: progress;
}

.ractro-button-link.is-loading:hover,
.ractro-button-link.is-loading:active {
    transform: none;
    box-shadow: none;
}

/* THE SPINNER.
 *
 * `1em`, so it tracks the button's font-size and therefore the size preset for
 * free — a Large button gets a large spinner with no second control and no
 * chance of the two drifting. btn_spinner_size overrides it when an author wants
 * something else.
 *
 * `currentColor` for the same reason the icon has no colour control (see
 * button.php): the spinner inherits the button's Text Color, so the common case
 * — they match — costs zero edits and cannot drift.
 *
 * `flex: none` because the link is an inline-flex row; without it the spinner is
 * a flex item that can be squashed to nothing by a long label.
 */
.ractro-button-spinner {
    display: inline-block;
    flex: none;
    width: 1em;
    height: 1em;
    border-radius: 50%;
    /* A ring with one transparent quadrant. Two colours on one element, no
       pseudo-element, no second node, no image request. */
    border: 2px solid currentColor;
    border-top-color: transparent;
    animation: ractro-btn-spin 0.7s linear infinite;
}

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

/* REDUCED MOTION.
 *
 * Stopping the animation is the easy half and on its own it is a regression: a
 * frozen ring with a gap in it reads as a broken circle, not as "busy", so the
 * only visual signal the state had would be replaced by what looks like a
 * rendering fault. So the gap closes too — the spinner becomes a complete, dimmed
 * ring, which is a static badge that still says "something is happening" — and
 * `aria-busy="true"` on the button carries the meaning for anyone who is not
 * reading the shape at all.
 *
 * The `.is-loading` scoping is not decoration: it keeps this override tied to
 * the state rather than to the element, matching every other rule in this file.
 */
@media (prefers-reduced-motion: reduce) {
    .ractro-button-link.is-loading .ractro-button-spinner {
        animation: none;
        border-top-color: currentColor;
        opacity: 0.5;
    }
}
