/* ─── Buttons ────────────────────────────────────────────────────────
   !important is scoped to `color` and `background` only — those fight
   `a:visited` from per-client main.css (links styled as buttons would
   otherwise shift to the visited color). All other properties (padding,
   border, border-radius, text-decoration) win on class specificity alone
   and do not need !important. See bottom-of-file note on why buttons
   intentionally use !important here instead of `.hzo-btn:visited` rules. */
/* Button component tokens (Hozio Studio Live, Phase 2a). Each property reads a
   --btn-* token that DEFAULTS (via the var() fallback) to the original semantic
   value — so with no override the render is byte-identical, and the design
   widget can override any of them per variant. "Linked by default": the
   fallback IS the link to --accent / --brand; an override breaks just that link. */
/* Variant sheets — @imported here so the component loader (which enqueues only
   buttons.css) pulls them on the same request (widget convention; precedent:
   carousel, tooltip). primitives.css also imports button-icon-slide.css
   directly for the monolith path — the duplicate rules are identical, so the
   cascade is unchanged. */
@import './button-icon-slide.css?ver=1787769613';

.hzo-btn,
.hzo-button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-sm);
    padding: var(--btn-padding-y, 14px) var(--btn-padding-x, 32px);
    font-family: var(--font-body);
    font-size: 1rem;
    font-weight: var(--btn-weight, var(--fw-semibold, 600));
    text-decoration: none;
    border-radius: var(--btn-radius, var(--radius-pill));
    border: var(--border-1) solid transparent;
    cursor: pointer;
    transition: background var(--transition-base), border-color var(--transition-base), color var(--transition-base), box-shadow var(--transition-base), transform 0.1s;
    min-height: 48px;
    line-height: var(--lh-none);
    white-space: nowrap;
    background: var(--btn-primary-bg, var(--accent)) !important;
    color: var(--btn-primary-text, var(--text-on-accent)) !important;
}
/* PF-042: both tokens are DECLARED in tokens.css now, so the inline fallbacks
   below are unreachable — kept only as a record of what this path used to
   resolve to. The old comment here claimed "bg darkens on hover → flip text
   light for contrast"; that assumption was never checked and measured 2.62:1 on
   a live client (and 2.19:1 at the engine's own default accent). See the
   --btn-primary-hover block in tokens.css for the measurements and for what is
   still NOT fixed. */
.hzo-btn:hover, .hzo-btn.is-hover,
.hzo-button:hover, .hzo-button.is-hover {
    background: var(--btn-primary-hover, var(--accent-hover-on-light)) !important;
    color: var(--btn-primary-hover-text, #fff) !important;
}
.hzo-btn:focus-visible, .hzo-btn.is-focus,
.hzo-button:focus-visible, .hzo-button.is-focus {
    outline: 3px solid var(--color-focus);
    outline-offset: 2px;
}
.hzo-btn.is-active, .hzo-btn:active,
.hzo-button.is-active, .hzo-button:active { transform: translateY(1px); }
.hzo-btn.is-disabled, .hzo-btn[disabled], .hzo-btn[aria-disabled="true"],
.hzo-button.is-disabled, .hzo-button[disabled], .hzo-button[aria-disabled="true"] {
    opacity: var(--opacity-disabled);
    pointer-events: none;
}

.hzo-btn--primary,
.hzo-button--primary {
    background: var(--btn-primary-bg, var(--accent)) !important;
    color: var(--btn-primary-text, var(--text-on-accent)) !important;
    border-color: var(--btn-primary-bg, var(--accent));
}
/* PF-042: this path used to darken to a DIFFERENT colour than bare .hzo-btn
   above (--accent-text vs --accent-hover-on-light), because --btn-primary-hover
   was undeclared and the two fallbacks disagreed — so a site got one of two
   hover colours depending on whether the author wrote the variant class.
   Declaring the token reconciles them; these fallbacks are now unreachable. */
.hzo-btn--primary:hover,
.hzo-button--primary:hover {
    background: var(--btn-primary-hover, var(--accent-text)) !important;
    border-color: var(--btn-primary-hover, var(--accent-text));
    color: var(--btn-primary-hover-text, #fff) !important;
}
.hzo-btn--secondary,
.hzo-button--secondary {
    background: var(--btn-secondary-bg, var(--brand)) !important;
    color: var(--btn-secondary-text, var(--text-on-brand)) !important;
    border-color: var(--btn-secondary-bg, var(--brand));
}
.hzo-btn--secondary:hover,
.hzo-button--secondary:hover {
    background: var(--btn-secondary-hover, var(--brand-hover-on-light)) !important;
    border-color: var(--btn-secondary-hover, var(--brand-hover-on-light));
    color: var(--btn-secondary-text, var(--text-on-brand)) !important;
}
.hzo-btn--outline,
.hzo-button--outline {
    background: transparent !important;
    color: var(--btn-outline-color, var(--brand)) !important;
    border-color: var(--btn-outline-color, var(--brand));
}
.hzo-btn--outline:hover,
.hzo-button--outline:hover {
    background: var(--btn-outline-color, var(--brand)) !important;
    color: var(--btn-secondary-text, var(--text-on-brand)) !important;
    border-color: var(--btn-outline-color, var(--brand));
}
.hzo-btn--ghost,
.hzo-button--ghost {
    background: transparent !important;
    color: var(--btn-ghost-color, var(--brand)) !important;
    border-color: transparent;
}
.hzo-btn--ghost:hover,
.hzo-button--ghost:hover {
    background: var(--btn-ghost-hover, var(--brand-pale)) !important;
    color: var(--btn-ghost-color, var(--brand)) !important;
}
/* Tertiary — the quiet FILLED tier, and the missing rung on this ladder.
   Between --outline (a brand-coloured border, which is loud) and --ghost
   (transparent, which has no rest-state affordance at all on a light surface),
   there was nothing: a neutral, obviously-clickable, obviously-subordinate
   action. That gap is why dense UI ("Load more", "Filters", "Back to all
   services", pagination-adjacent actions) kept reaching for --outline and
   putting three brand-coloured borders in one row.

   Neutral by design: it reads --bg-alt / --border / --text-heading, no brand
   colour at all, so it can never compete with the primary. It IS visible at
   rest, which is the whole point and the reason it is not just another ghost.
   Hover deepens the fill and the border together (two properties, per the
   interaction-state rule) using color-mix off its own tokens, so it retints
   automatically with a client's neutrals. */
.hzo-btn--tertiary,
.hzo-button--tertiary {
    background: var(--btn-tertiary-bg, var(--bg-alt)) !important;
    color: var(--btn-tertiary-text, var(--text-heading)) !important;
    border-color: var(--btn-tertiary-border, var(--border));
}
.hzo-btn--tertiary:hover,
.hzo-button--tertiary:hover {
    background: var(--btn-tertiary-hover, color-mix(in srgb, var(--btn-tertiary-bg, var(--bg-alt)) 88%, var(--btn-tertiary-text, var(--text-heading)))) !important;
    color: var(--btn-tertiary-text, var(--text-heading)) !important;
    border-color: var(--btn-tertiary-hover-border, var(--text-muted));
}
.hzo-btn--danger,
.hzo-button--danger {
    background: var(--btn-danger-bg, var(--error)) !important;
    color: #fff !important;
    border-color: var(--btn-danger-bg, var(--error));
}
.hzo-btn--danger:hover,
.hzo-button--danger:hover {
    background: var(--btn-danger-hover, #B91C1C) !important;
    border-color: var(--btn-danger-hover, #B91C1C);
    color: #fff !important;
}

/* A little depth on hover so filled buttons feel tactile instead of flat — a
   default-polish touch; per-client themes still control everything via --btn-*.
   Selector list carries the S4 .hzo-button alias so both vocabularies match. */
.hzo-btn--primary:hover,
.hzo-btn--secondary:hover,
.hzo-btn--danger:hover,
.hzo-button--primary:hover,
.hzo-button--secondary:hover,
.hzo-button--danger:hover { box-shadow: var(--shadow-md); }

.hzo-btn--sm,
.hzo-button--sm { padding: calc(var(--btn-padding-y, 14px) - 4px) calc(var(--btn-padding-x, 32px) - 10px); font-size: 0.875rem; min-height: 36px; }
.hzo-btn--lg,
.hzo-button--lg { padding: calc(var(--btn-padding-y, 14px) + 2px) calc(var(--btn-padding-x, 32px) + 8px); font-size: 1.125rem; min-height: 52px; }

/* Full-width — stretches to the container at all breakpoints. (Mobile already
   stretches non-inline buttons; this opts desktop in too — e.g. a form submit
   or a stacked CTA pair on a narrow card.) */
.hzo-btn--block,
.hzo-button--block { width: 100%; }

/* Icon-only — square button sized to the button height, for a lone icon
   (search / menu / close, nav arrows, social). Pair with --sm / --lg to
   resize. Always intrinsic width (excluded from the mobile full-width rule
   below). The author MUST supply an aria-label — there is no text node. */
.hzo-btn--icon,
.hzo-button--icon { padding: 0; width: 48px; min-width: 48px; }
.hzo-btn--icon.hzo-btn--sm,
.hzo-button--icon.hzo-button--sm { width: 36px; min-width: 36px; }
.hzo-btn--icon.hzo-btn--lg,
.hzo-button--icon.hzo-button--lg { width: 52px; min-width: 52px; }
.hzo-btn--icon > svg,
.hzo-button--icon > svg { width: 20px; height: 20px; }

/* Link button — button semantics, link appearance. For the lowest-emphasis
   inline actions ("Cancel", "Skip"). !important on color/background matches the
   base button rules so it wins the per-client a:visited fight (see the
   bottom-of-file note) — no stale :visited rule needed. */
.hzo-btn--link,
.hzo-button--link {
    background: transparent !important;
    color: var(--brand-text) !important;
    border-color: transparent;
    min-height: 0;
    padding: var(--space-xs) 0;
    border-radius: var(--radius-0);
    text-decoration: underline;
    text-underline-offset: 3px;
}
.hzo-btn--link:hover,
.hzo-button--link:hover {
    background: transparent !important;
    color: var(--brand-hover-on-dark) !important;
    text-decoration-thickness: 2px;
}
.hzo-btn--on-dark.hzo-btn--link,
.hzo-btn--on-dark.hzo-btn--link:hover,
.hzo-button--on-dark.hzo-button--link,
.hzo-button--on-dark.hzo-button--link:hover { color: #fff !important; }

/* Mobile: buttons go full-width by default for easier tapping + stacked
   layout. Opt out with .hzo-btn--inline when a button needs to stay
   intrinsic width on mobile (side-by-side pairs, etc.). Icon + link buttons
   are intrinsic-width by nature, so they're excluded too. */
@media (max-width: 767px) {
    .hzo-btn:not(.hzo-btn--inline):not(.hzo-btn--icon):not(.hzo-btn--link),
.hzo-button:not(.hzo-button--inline):not(.hzo-button--icon):not(.hzo-button--link) { width: 100%; }
}

/* ═══ MODIFIER vs VARIANT — the contract (PF-062) ══════════════════════════
   Read this before adding any class to this file.

   A VARIANT answers "which button is this": --primary, --secondary, --outline,
   --ghost, --tertiary, --link, --danger. Exactly one per button. It sets the
   fill, the ink and the border.

   A MODIFIER answers "under what conditions": --on-dark, --sm, --lg, --block,
   --inline, --icon. Zero or more. It ADJUSTS a variant. It must never be the
   only thing a button carries and expect to look like anything.

   THE FAILURE THIS PREVENTS. Before Wave S every --on-dark rule in this file
   was written as a COMPOUND (.hzo-btn--on-dark.hzo-btn--secondary, …), so
   `class="hzo-btn hzo-btn--on-dark hzo-btn--lg"` matched no on-dark rule at
   all, fell through to the base .hzo-btn, and rendered as the ACCENT FILL —
   a second primary button, sitting next to the real primary, with no visual
   hierarchy between them. Nothing errored. The class was real, the markup
   looked deliberate, the button rendered perfectly. It was visible only in a
   screenshot, and the engine shipped it in its own reference patterns.

   TWO RULES FOLLOW, and both are enforced below:
   1. Every modifier gets a BARE fallback that degrades to something sensible,
      so a missing variant is a slightly-wrong button rather than a silently
      wrong one.
   2. Reference patterns name the variant explicitly. A pattern is a teaching
      surface; it should model the contract, not the shorthand.

   When adding a new modifier to this file, write its bare rule first.
   ═══════════════════════════════════════════════════════════════════════════ */

/* BARE --on-dark FALLBACK (PF-062). Degrades to the on-dark OUTLINE treatment:
   transparent fill, white ink, white border. That is the one answer correct in
   BOTH on-dark contexts — over a photo (where a filled secondary fights the
   image) and over a solid brand band (where an outline is clearly subordinate
   to the accent primary).

   The :not() chain is load-bearing, not defensive noise. This rule is declared
   AFTER the variant rules above, and `.hzo-btn--on-dark` alone is (0,1,0) —
   the same specificity as `.hzo-btn--primary`. Without the exclusions it would
   win on source order and silently turn every correctly-authored
   `--primary --on-dark` button into an outline. Every variant in this file
   must appear in the chain; add new ones here when you add them above. */
.hzo-btn--on-dark:not(.hzo-btn--primary):not(.hzo-btn--secondary):not(.hzo-btn--tertiary):not(.hzo-btn--outline):not(.hzo-btn--ghost):not(.hzo-btn--link):not(.hzo-btn--danger),
.hzo-button--on-dark:not(.hzo-button--primary):not(.hzo-button--secondary):not(.hzo-button--tertiary):not(.hzo-button--outline):not(.hzo-button--ghost):not(.hzo-button--link):not(.hzo-button--danger) {
    background: transparent !important;
    color: var(--btn-on-dark-accent, #fff) !important;
    border-color: var(--btn-on-dark-accent, #fff);
}
.hzo-btn--on-dark:not(.hzo-btn--primary):not(.hzo-btn--secondary):not(.hzo-btn--tertiary):not(.hzo-btn--outline):not(.hzo-btn--ghost):not(.hzo-btn--link):not(.hzo-btn--danger):hover,
.hzo-button--on-dark:not(.hzo-button--primary):not(.hzo-button--secondary):not(.hzo-button--tertiary):not(.hzo-button--outline):not(.hzo-button--ghost):not(.hzo-button--link):not(.hzo-button--danger):hover {
    background: var(--btn-on-dark-accent, #fff) !important;
    color: var(--btn-on-dark-text, var(--brand)) !important;
}

/* Dark-section button overrides.
   On brand-colored dark sections, the SECONDARY button (now blue) would
   disappear since it shares the section's color. Flip it to a white button
   with brand text for clear visibility. Primary (green) stays green — it
   has plenty of contrast against blue — and its hover gets the lighter
   on-dark variant for extra feedback. !important on color/background
   matches base rules so on-dark variants win the :visited fight. */
.hzo-btn--on-dark.hzo-btn--primary:hover,
.hzo-button--on-dark.hzo-button--primary:hover {
    /* Palest-accent fill on dark — accent family, lightest stop (--accent-pale);
       the dark accent-on-fill text (--text-on-accent) reads cleanly on it. */
    background: var(--accent-pale) !important;
    border-color: var(--accent-pale);
    color: var(--text-on-accent) !important;
}
.hzo-btn--on-dark.hzo-btn--secondary,
.hzo-button--on-dark.hzo-button--secondary {
    background: var(--btn-on-dark-bg, #fff) !important;
    color: var(--btn-on-dark-text, var(--brand)) !important;
    border-color: var(--btn-on-dark-bg, #fff);
}
.hzo-btn--on-dark.hzo-btn--secondary:hover,
.hzo-button--on-dark.hzo-button--secondary:hover {
    /* Clear branded tint away from white so the hover obviously reads. */
    background: color-mix(in srgb, var(--btn-on-dark-bg, #ffffff) 75%, var(--btn-on-dark-text, var(--brand))) !important;
    border-color: color-mix(in srgb, var(--btn-on-dark-bg, #ffffff) 75%, var(--btn-on-dark-text, var(--brand)));
    color: var(--brand-hover-on-light) !important;
}
.hzo-btn--on-dark.hzo-btn--outline,
.hzo-button--on-dark.hzo-button--outline {
    color: var(--btn-on-dark-accent, #fff) !important;
    border-color: var(--btn-on-dark-accent, #fff);
    background: transparent !important;
}
.hzo-btn--on-dark.hzo-btn--outline:hover,
.hzo-button--on-dark.hzo-button--outline:hover {
    background: var(--btn-on-dark-accent, #fff) !important;
    color: var(--btn-on-dark-text, var(--brand)) !important;
}
/* Tertiary on dark — the same "quiet but visible" job, inverted: a low-opacity
   white veil rather than the light neutral fill, which would read as a second
   white (secondary) button on a dark band. */
.hzo-btn--on-dark.hzo-btn--tertiary,
.hzo-button--on-dark.hzo-button--tertiary {
    background: rgba(255, 255, 255, 0.14) !important;
    color: var(--btn-on-dark-accent, #fff) !important;
    border-color: rgba(255, 255, 255, 0.34);
}
.hzo-btn--on-dark.hzo-btn--tertiary:hover,
.hzo-button--on-dark.hzo-button--tertiary:hover {
    background: rgba(255, 255, 255, 0.26) !important;
    color: var(--btn-on-dark-accent, #fff) !important;
    border-color: rgba(255, 255, 255, 0.55);
}
.hzo-btn--on-dark.hzo-btn--ghost,
.hzo-button--on-dark.hzo-button--ghost { color: var(--btn-on-dark-accent, #fff) !important; }
.hzo-btn--on-dark.hzo-btn--ghost:hover,
.hzo-button--on-dark.hzo-button--ghost:hover {
    background: rgba(255,255,255,0.2) !important;
    color: var(--btn-on-dark-accent, #fff) !important;
}

/* Loading state — add `is-loading` + `aria-busy="true"`. The label is hidden
   (color → transparent) and a spinner is painted centered; the label still
   occupies space so the button keeps its width and doesn't reflow. pointer-
   events off blocks a double-submit. The ring color is set per variant so it
   reads on each background. */
.hzo-btn.is-loading,
.hzo-button.is-loading {
    color: transparent !important;
    pointer-events: none;
    position: relative;
}
.hzo-btn.is-loading::after,
.hzo-button.is-loading::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: 18px;
    height: 18px;
    margin: -9px 0 0 -9px;
    border-radius: 50%;
    /* Default: dark ring, reads on the accent/primary fill. */
    border: var(--border-2) solid color-mix(in srgb, var(--text-on-accent) 30%, transparent);
    border-top-color: var(--text-on-accent);
    animation: hzo-spin 0.6s linear infinite;
}
/* Filled-dark variants → white ring. */
.hzo-btn--secondary.is-loading::after,
.hzo-btn--danger.is-loading::after,
.hzo-button--secondary.is-loading::after,
.hzo-button--danger.is-loading::after {
    border-color: rgba(255, 255, 255, 0.35);
    border-top-color: #fff;
}
/* Transparent variants → brand ring. */
.hzo-btn--outline.is-loading::after,
.hzo-btn--ghost.is-loading::after,
.hzo-btn--link.is-loading::after,
.hzo-button--outline.is-loading::after,
.hzo-button--ghost.is-loading::after,
.hzo-button--link.is-loading::after {
    border-color: color-mix(in srgb, var(--brand) 30%, transparent);
    border-top-color: var(--brand);
}
@media (prefers-reduced-motion: reduce) {
    .hzo-btn.is-loading::after,
.hzo-button.is-loading::after { animation-duration: 1.5s; }
}

/* Added confirmation (add-to-cart) — briefly swaps the label for a success check
   after a successful add. Mirrors `.is-loading`: label hidden, glyph centered, no
   reflow, pointer-events off. The JS driver (buttons.js, this folder) toggles it on, fires
   hzo.toast('Added to cart'), then reverts to default after a short window. It's a
   state swap, not an animation, so it's reduced-motion-safe by construction. An
   integration wanting a persistent state sets the label to "In cart" instead. */
.hzo-btn.is-added,
.hzo-button.is-added {
    color: transparent !important;
    pointer-events: none;
    position: relative;
}
.hzo-btn.is-added::after,
.hzo-button.is-added::after {
    content: "\2713"; /* ✓ */
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    font-size: 1.15em;
    font-weight: var(--fw-700);
    line-height: var(--lh-none);
    color: var(--text-on-accent); /* reads on the primary/accent fill */
}
.hzo-btn--secondary.is-added::after,
.hzo-btn--danger.is-added::after,
.hzo-button--secondary.is-added::after,
.hzo-button--danger.is-added::after { color: #fff; }
.hzo-btn--outline.is-added::after,
.hzo-btn--ghost.is-added::after,
.hzo-btn--link.is-added::after,
.hzo-button--outline.is-added::after,
.hzo-button--ghost.is-added::after,
.hzo-button--link.is-added::after { color: var(--brand); }
/* Tertiary's fill is neutral, so the check takes the neutral heading ink
   rather than the brand (which would be the only brand-coloured thing on an
   intentionally brand-free button). */
.hzo-btn--tertiary.is-added::after,
.hzo-button--tertiary.is-added::after { color: var(--btn-tertiary-text, var(--text-heading)); }
