/* ========== INLINE FORM VALIDATION ==========
   Pairs with native HTML5 constraint validation (`required`, `type="email"`,
   `pattern`, `minlength`, …) and the auto-binding helper in
   /public/js/form-validate.js.

   Uses :user-invalid / :user-valid (Chrome 119+, Safari 16.5+, Firefox 88+ —
   essentially universal in 2026). These pseudo-classes match only AFTER the
   user has interacted with the field, so untouched fields don't shout red on
   first render. Older browsers gracefully degrade — they just don't get the
   inline styling, and the auto-binding JS still surfaces messages on submit.

   Selectors are scoped to `.form-group` (the wrapper used everywhere on this
   site) rather than `.form-control` (the class). Some forms — notably
   contact.ejs — have inputs styled via `.form-group input` without the
   `form-control` class; this scoping covers both conventions. */

/* Error palette — uses the --status-cancelled token defined per theme in
   base.css (#c25a5a dark, #a8474a light). A warm brick red, not the flat-UI
   emergency red. Sits alongside the gold accent and bordeaux tones without
   fighting the palette. */

/* Visible required-field marker. Auto-applied to any label whose immediately-
   following sibling is a required input/select/textarea, so views never need
   to remember to add a `.required` class. Uses CSS :has() (Safari 15.4+,
   Chrome 105+, Firefox 121+ — universal in 2026). Browsers without :has()
   simply don't show the asterisk; the underlying `required` attribute and
   inline-validation styling still apply. */
.form-group label:has(+ input[required])::after,
.form-group label:has(+ select[required])::after,
.form-group label:has(+ textarea[required])::after,
.form-group label:has(+ .form-control[required])::after {
  content: ' *';
  color: var(--accent-text);
  font-weight: 600;
  /* Decorative — screen readers announce "required" via the input itself,
     so the asterisk is visual only. */
}

/* Touched + invalid + not currently focused → red border + subtle warm
   background tint so the field reads as "this has a problem". We exclude
   :focus so the field doesn't shout while the user is actively typing. */
.form-group :user-invalid:not(:focus) {
  border-color: var(--status-cancelled);
  background-color: color-mix(in srgb, var(--status-cancelled) 6%, transparent);
}

/* Touched + valid → subtle gold tint. Restricted to fields that have an
   actual constraint, otherwise every typed-into text field would highlight
   (since fields without constraints are vacuously valid). Gold reads as
   "approved / settled" in this palette — was bright Bootstrap green prior. */
.form-group
  :is(
    :required,
    [pattern],
    [type='email'],
    [type='tel'],
    [type='url'],
    [type='number'],
    [minlength],
    [maxlength]
  ):user-valid {
  border-color: color-mix(in srgb, var(--accent) 55%, transparent);
}

/* Sibling error text — JS surfaces validationMessage here on submit.
   The leading 2px bar makes it feel like a deliberate inline alert rather
   than free-floating red text, and matches the editorial bar treatment
   used elsewhere on the site (hero subtitle, summary highlights). */
.form-error {
  display: none;
  margin-top: 0.5rem;
  padding: 0.15rem 0 0.15rem 0.7rem;
  border-left: 2px solid var(--status-cancelled);
  font-size: 0.85rem;
  color: var(--status-cancelled);
  font-weight: 500;
  line-height: 1.5;
}

.form-error.visible {
  display: block;
}

/* ========== FORM-LEVEL ALERTS ==========
   Top-of-form / step-of-form messaging — distinct from .form-error which is
   the single-line note under one field. .form-alert is the bordered block
   for things like "incorrect password", "this date is unavailable", or
   "step 2 has missing fields". Previously duplicated inline as .auth-error,
   .auth-success, .booking-error, .booking-validation-msg across 5 view files
   with off-brand flat-UI colours; now one component.

   Variants:
     .form-alert--error    warm brick red, matches .form-error palette
     .form-alert--success  brand gold (intentionally not green — gold reads
                           as "settled / good" in this palette)
     .form-alert--toggle   defaults hidden, opt-in for JS-driven reveal via
                           the existing .visible class (used by book.ejs's
                           per-step validation messages) */
.form-alert {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
  padding: 0.85rem 1.1rem;
  margin-bottom: 1.5rem;
  border-left: 3px solid currentColor;
  border-radius: var(--radius-md);
  font-weight: 500;
  font-size: 0.9rem;
  line-height: 1.5;
}

.form-alert--error {
  background: color-mix(in srgb, var(--status-cancelled) 10%, transparent);
  color: var(--status-cancelled);
}

.form-alert--success {
  background: color-mix(in srgb, var(--accent) 10%, transparent);
  color: var(--accent-text);
}

.form-alert--toggle {
  display: none;
}
.form-alert--toggle.visible {
  display: flex;
}

/* ========== SUBMIT BUTTON LOADING STATE ==========
   Applied by form-validate.js to any submit button on a form with
   data-loading-on-submit. Prevents double-clicks while the user waits for
   the server response (Stripe redirect, contact submission, etc.) and gives
   visible feedback that something is happening. */
.btn-loading {
  pointer-events: none;
}

.btn-loading::before {
  content: '';
  display: inline-block;
  width: 14px;
  height: 14px;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  margin-right: 0.6rem;
  vertical-align: -2px;
  animation: btn-spinner-rotate 0.6s linear infinite;
}

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

@media (prefers-reduced-motion: reduce) {
  .btn-loading::before {
    animation: none;
  }
}

.recaptcha-attribution {
  font-size: 0.78rem;
  opacity: 0.65;
  line-height: 1.5;
  margin: 1rem 0 0.5rem;
}
.recaptcha-attribution a {
  color: inherit;
  text-decoration: underline;
}

/* Hide Google's floating reCAPTCHA badge (bottom-right corner of every page
   the v3 script loads on). Google's terms allow hiding the badge as long
   as the reCAPTCHA branding stays visible in the user flow — handled by
   the `.recaptcha-attribution` paragraph in `views/partials/recaptcha.ejs`,
   included inside every protected form (book / contact / login / register
   / forgot). Use `visibility: hidden` not `display: none`: the widget's
   iframe still needs to render so v3 can compute its risk score; only the
   visual badge is suppressed. */
.grecaptcha-badge {
  visibility: hidden;
}
