/* ============================================================
   STANDARD BUTTON MOTION

   Every button in the app moves the same way, borrowing the motion signature
   of the sliding nav pill: a spring that slightly overshoots and settles,
   cubic-bezier(0.34, 1.4, 0.64, 1).

   The pill itself is a *group* effect — one shared element travelling between
   sibling tabs — so it cannot literally apply to a lone button. What carries
   over is the feel: press-ready lift, spring settle, quick decisive press.

   WHY TRANSFORM + SHADOW + BRIGHTNESS, AND NOT AN OVERLAY
   An added ::before highlight would have to sit above each button's own
   background but below its label, and these buttons have wildly different
   backgrounds (gradient, tinted, ghost, bare). Getting that stacking right for
   every one is fragile. transform, box-shadow and filter compose with whatever
   background a button already has, so one rule works everywhere and no existing
   button style needs rewriting.

   LOAD ORDER MATTERS: link this AFTER admin.css / styles.css. Several buttons
   already declare their own :hover transform, and this file has to outrank
   them — partly on specificity (see the :not() note below) and partly on
   source order. Linked first, it loses both ways.

   Shared by the public form and the admin dashboard; both link this file so the
   standard cannot drift between them.
   ============================================================ */

:root {
  /* Overshoot-and-settle. Same curve as .pill-indicator, the sliding highlight
     on the nav and every other tab group. */
  --btn-spring: cubic-bezier(0.34, 1.4, 0.64, 1);
  --btn-dur: 0.26s;
  /* A press should feel immediate — springing back on the way down feels mushy. */
  --btn-press-dur: 0.09s;
  --btn-lift: -2px;
}

/* `button` is included as a bare element so unclassed buttons are covered too;
   [class*="-btn"] sweeps up action-btn / admin-btn / reject-btn / icon-btn and
   the rest without having to enumerate 25 names and keep the list current.
   :is() takes the specificity of its most specific argument — here the
   attribute selector, (0,1,0).

   The :not()s are not decoration — they carry specificity. A plain
   :is(...) list is (0,1,0), which loses to an existing rule like
   `.admin-nav-logout button` (0,1,1). That combination is the worst outcome:
   the more specific rule keeps its own short transition while the hover rule
   below still applies the lift, so the button JUMPS instead of springing.
   Each :not() adds a class-level unit, putting this at (0,3,0) — above any
   single-class rule — and the disabled exclusions are wanted anyway. */
:is(button, .btn, [class*="-btn"], .chat-send, .chat-close, .admin-nav-view-form):not(:disabled):not([aria-disabled="true"]) {
  transition:
    transform var(--btn-dur) var(--btn-spring),
    box-shadow var(--btn-dur) var(--btn-spring),
    filter 0.18s ease,
    background 0.15s ease,
    border-color 0.15s ease,
    color 0.15s ease;
  /* Stops the lift from resampling text blurrily mid-transform. */
  backface-visibility: hidden;
}

/* The nav pill's look, per button: a tinted fill plus a 1px ring, springing in.
 *
 * Built from inset box-shadows rather than an overlay element. An inset shadow
 * paints above the button's own background but below its label, needs no
 * stacking context, and cannot collide with the ::before/::after that several
 * buttons already use for carets and icons. The 999px spread is simply "fill
 * the whole button" — inset shadows clip to the border radius for free.
 *
 * The tint is currentColor, so every button glows in ITS OWN colour: Approve
 * green, Reject red, ghost buttons blue. One rule, and the colour is never
 * wrong because it is the colour the button already uses. */
:is(button, .btn, [class*="-btn"], .chat-send, .chat-close, .admin-nav-view-form):hover:not(:disabled):not([aria-disabled="true"]) {
  transform: translateY(var(--btn-lift));
  box-shadow:
    inset 0 0 0 999px color-mix(in srgb, currentColor 13%, transparent),
    inset 0 0 0 1px   color-mix(in srgb, currentColor 26%, transparent);
  /* Light, because the fill above is already doing most of the lifting —
     together they used to read as a blown-out button. */
  filter: brightness(1.04);
}

/* Press beats hover: settle back down, contract slightly, deepen the fill, and
   do it fast. */
:is(button, .btn, [class*="-btn"], .chat-send, .chat-close, .admin-nav-view-form):active:not(:disabled):not([aria-disabled="true"]) {
  transform: translateY(0) scale(0.97);
  transition-duration: var(--btn-press-dur);
  box-shadow:
    inset 0 0 0 999px color-mix(in srgb, currentColor 17%, transparent),
    inset 0 0 0 1px   color-mix(in srgb, currentColor 40%, transparent);
  filter: brightness(0.98);
}

:is(button, .btn, [class*="-btn"], .chat-send, .chat-close, .admin-nav-view-form):disabled,
:is(button, .btn, [class*="-btn"], .chat-send, .chat-close, .admin-nav-view-form)[aria-disabled="true"] {
  transform: none;
  filter: none;
}

/* Keyboard users get the same affordance as the pointer, plus a visible ring. */
:is(button, .btn, [class*="-btn"], .chat-send, .chat-close, .admin-nav-view-form):focus-visible {
  outline: 2px solid var(--blue, #47b5ff);
  outline-offset: 2px;
}

/* Anything inside a sliding-highlight group is excluded: the travelling pill
   already owns the hover, and the button fill on top of it reads as two
   effects fighting — a chip that lights up AND a highlight arriving.
 *
 * The nav's items are <a> tags, so they never matched the button selectors
 * anyway, but the other groups are real <button>s and did. Specificity here is
 * (0,4,0) — the same as the :hover rule above — so these win on source order,
 * which is why they must stay below it. The :not(:disabled) is what supplies
 * the fourth unit; without it these would lose. */
.admin-nav-links a:hover,
.admin-nav-links a:active,
.view-toggle .vt-btn:hover:not(:disabled),
.view-toggle .vt-btn:active:not(:disabled),
.section-tabs .section-tab:hover:not(:disabled),
.section-tabs .section-tab:active:not(:disabled),
.sh-tabs .sh-tab:hover:not(:disabled),
.sh-tabs .sh-tab:active:not(:disabled) {
  transform: none;
  box-shadow: none;
  filter: none;
}

/* Chat avatars are buttons (click one to mention that person), but they carry
   an inline gradient and their own lift-and-unstack hover. The standard inset
   fill would wash that gradient out and the two transforms would fight.
   Drawer-scoped to reach (0,4,0) — the same specificity as the :hover rule
   above — so it wins on source order. */
.chat-drawer .chat-ava-pick:hover:not(:disabled),
.chat-drawer .chat-ava-pick:active:not(:disabled) {
  box-shadow: none;
  filter: none;
}

/* The blast button is the one filled button in the app with WHITE text on a
   saturated fill, and the rule above tints with currentColor — which here is
   white. That washes the red toward pink on hover: it gets lighter and friendlier
   at exactly the moment it should feel heavier. Swap the tint for a dark one so
   hover deepens the colour, and keep the lift.

   Specificity is (0,4,0) — two classes plus :hover plus :not() — matching the
   :hover rule above, so this wins on source order, which is why it must stay
   below it. Same arithmetic as the chat-avatar exception. */
.showbar-cta .showbar-blast:hover:not(:disabled),
.blast-actions .showbar-blast:hover:not(:disabled) {
  box-shadow:
    inset 0 0 0 999px rgba(0, 0, 0, 0.16),
    0 4px 14px color-mix(in srgb, var(--rejected) 40%, transparent);
  filter: none;
}
.showbar-cta .showbar-blast:active:not(:disabled),
.blast-actions .showbar-blast:active:not(:disabled) {
  box-shadow: inset 0 0 0 999px rgba(0, 0, 0, 0.26);
  filter: none;
}

/* Motion is the whole point here, so with reduced motion the buttons keep the
   feedback and drop only the movement. */
@media (prefers-reduced-motion: reduce) {
  :is(button, .btn, [class*="-btn"], .chat-send, .chat-close, .admin-nav-view-form):not(:disabled):not([aria-disabled="true"]) {
    transition: filter 0.18s ease, background 0.15s ease,
                border-color 0.15s ease, color 0.15s ease;
  }
  :is(button, .btn, [class*="-btn"], .chat-send, .chat-close, .admin-nav-view-form):hover:not(:disabled),
  :is(button, .btn, [class*="-btn"], .chat-send, .chat-close, .admin-nav-view-form):active:not(:disabled) {
    transform: none;
  }
}
