/**
 * Bunny Reactions — Frontend Styles
 * Version: 0.2.0
 *
 * Design principles:
 *   - CSS custom properties for easy theming (no Sass needed).
 *   - Animations only on transform + opacity (GPU-composited, no reflow).
 *   - Reduced-motion respected globally.
 *   - Dark mode via prefers-color-scheme + custom property overrides.
 *   - No external fonts, no icon libraries, no dependencies.
 *
 * Classes applied by JS:
 *   .is-reacted   — user reacted successfully (persists via localStorage)
 *   .is-loading   — fetch in-flight (visual dimming)
 *   .is-pop       — pop keyframe animation (momentary, removed by JS)
 *   .is-shake     — shake keyframe animation (error / already-reacted)
 */

/* ── Design tokens ──────────────────────────────────────────────────────────
   Override any of these in your theme's CSS to restyle reactions globally.
   Example: .br { --br-color: #e91e63; }
   ────────────────────────────────────────────────────────────────────────── */
.br {
	/* Layout */
	--br-gap:            6px;
	--br-padding:        0.5em 1em;
	--br-radius:         999px;          /* pill shape */

	/* Typography */
	--br-font-size:      0.875rem;       /* 14px at 16px base */
	--br-emoji-size:     1.1em;

	/* Colors — light mode defaults */
	--br-color:          #555;
	--br-color-hover:    #FB5FAB;
	--br-color-reacted:  #e91e63;        /* hot pink — matches anime/waifu vibe */
	--br-color-pending:  #f57c00;        /* amber — "waiting to commit" */
	--br-bg:             transparent;
	--br-bg-hover:       rgba(0,0,0,0.05);
	--br-bg-reacted:     rgba(233,30,99,0.08);
	--br-bg-pending:     rgba(245,124,0,0.08);
	--br-border:         rgba(0,0,0,0.18);
	--br-border-hover:   rgba(0,0,0,0.35);
	--br-border-reacted: rgba(233,30,99,0.4);
	--br-border-pending: rgba(245,124,0,0.45);

	/* Transition */
	--br-speed:          0.18s;
	--br-ease:           cubic-bezier(0.34, 1.56, 0.64, 1); /* slight overshoot */

	/* Pending window duration — must match PENDING_MS in bunny-reactions.js */
	--br-pending-ms:     1500ms;
}

/* Dark mode — auto via media query */
@media (prefers-color-scheme: dark) {
	.br {
		--br-color:          #bbb;
		--br-color-hover:    #fff;
		--br-color-reacted:  #f06292;
		--br-color-pending:  #ffb74d;
		--br-bg-hover:       rgba(255,255,255,0.07);
		--br-bg-reacted:     rgba(240,98,146,0.12);
		--br-bg-pending:     rgba(255,183,77,0.10);
		--br-border:         rgba(255,255,255,0.18);
		--br-border-hover:   rgba(255,255,255,0.35);
		--br-border-reacted: rgba(240,98,146,0.45);
		--br-border-pending: rgba(255,183,77,0.45);
	}
}

/* ── Container ──────────────────────────────────────────────────────────────*/
.br {
	display:     flex;
	flex-wrap:   wrap;
	gap:         var(--br-gap);
	margin:      1.25em 0;
	padding:     0;
	list-style:  none;
	/* Ensure the bar never collapses on empty content */
	min-height:  2.5em;
}

/* ── Button base ────────────────────────────────────────────────────────────*/
.br-btn {
	/* Layout */
	display:         inline-flex;
	align-items:     center;
	gap:             0.35em;
	padding:         var(--br-padding);
	border-radius:   var(--br-radius);

	/* Appearance */
	background:      var(--br-bg);
	border:          1px solid var(--br-border);
	color:           var(--br-color);
	font-size:       var(--br-font-size);
	font-family:     inherit;
	line-height:     1;
	cursor:          pointer;

	/* Performance: promote to own layer to avoid repaints during animation */
	will-change:     transform;
	transform:       translateZ(0);

	/* Transition applies to all state changes EXCEPT animation keyframes */
	transition:
		background   var(--br-speed) ease,
		border-color var(--br-speed) ease,
		color        var(--br-speed) ease,
		opacity      var(--br-speed) ease;

	/* Reset browser button styles */
	-webkit-appearance: none;
	appearance:         none;
	user-select:        none;
}

/* ── Hover ──────────────────────────────────────────────────────────────────*/
.br-btn:hover,
.br-btn:focus-visible {
	background:   var(--br-bg-hover);
	border-color: var(--br-border-hover);
	color:        var(--br-color-hover);
	outline:      none;
}

/* Fix: reacted buttons keep their accent color on hover — no white flash */
.br-btn.is-reacted:hover,
.br-btn.is-reacted:focus-visible {
	background:   var(--br-bg-reacted);
	border-color: var(--br-border-reacted);
	color:        var(--br-color-reacted);
	opacity:      0.9;
}

/* Fix: pending buttons keep their pending accent on hover */
.br-btn.is-pending:hover,
.br-btn.is-pending:focus-visible {
	background:   var(--br-bg-pending);
	border-color: var(--br-border-pending);
	color:        var(--br-color-pending);
}

/* Explicit focus ring for keyboard nav (separate from hover) */
.br-btn:focus-visible {
	outline:        2px solid var(--br-color-reacted);
	outline-offset: 2px;
}

/* ── Reacted state ──────────────────────────────────────────────────────────
   Applied by JS after a successful reaction (persisted via localStorage).
   ────────────────────────────────────────────────────────────────────────── */
.br-btn.is-reacted {
	background:   var(--br-bg-reacted);
	border-color: var(--br-border-reacted);
	color:        var(--br-color-reacted);
}

/* Slightly bolder count when reacted */
.br-btn.is-reacted .br-count {
	font-weight: 600;
}

/* ── Loading state ──────────────────────────────────────────────────────────
   Applied by JS while the fetch() is in-flight (after pending window commits).
   ────────────────────────────────────────────────────────────────────────── */
.br-btn.is-loading {
	opacity: 0.65;
	cursor:  wait;
}

/* ── Pending state ──────────────────────────────────────────────────────────
   Applied immediately on first click. Button shows +1 count but fetch hasn't
   fired yet. A second click during this window cancels the reaction.
   A CSS progress underline shows the remaining time visually.
   ────────────────────────────────────────────────────────────────────────── */
.br-btn.is-pending {
	background:   var(--br-bg-pending);
	border-color: var(--br-border-pending);
	color:        var(--br-color-pending);
	cursor:       pointer; /* still clickable — second click cancels */
	position:     relative;
	overflow:     hidden;  /* clip the progress bar */
}

/* Progress bar: shrinks from 100% → 0% over --br-pending-ms */
.br-btn.is-pending::after {
	content:          '';
	position:         absolute;
	bottom:           0;
	left:             0;
	height:           2px;
	width:            100%;
	background:       var(--br-color-pending);
	transform-origin: left center;
	animation:        br-progress var(--br-pending-ms) linear forwards;
}

@keyframes br-progress {
	from { transform: scaleX(1); }
	to   { transform: scaleX(0); }
}

/* ── Cancelled state ────────────────────────────────────────────────────────
   Momentary class added by JS on cancel. Gives brief visual confirmation
   that the second click registered as a cancellation, not a new reaction.
   Class is removed by the animationend listener in triggerClass().
   ────────────────────────────────────────────────────────────────────────── */
.br-btn.is-cancelled {
	animation: br-cancelled 0.4s ease forwards;
}

@keyframes br-cancelled {
	0%   { opacity: 1;    transform: scale(1); }
	30%  { opacity: 0.5;  transform: scale(0.93); }
	100% { opacity: 1;    transform: scale(1); }
}

/* ── Emoji ──────────────────────────────────────────────────────────────────*/
.br-emoji {
	font-size:    var(--br-emoji-size);
	line-height:  1;
	/* Prevent emoji from being selected when user double-clicks */
	user-select:  none;
	/* Stabilize emoji width across OS renderers */
	display:      inline-block;
}

/* ── Count ──────────────────────────────────────────────────────────────────*/
.br-count {
	/* Tabular nums prevent layout shift as numbers change */
	font-variant-numeric: tabular-nums;
	/* Reserve at least 2 chars of width so the button doesn't resize on update */
	min-width:            1.6ch;
	text-align:           right;
	transition:           font-weight var(--br-speed) ease;
}

/* ── Micro-animations ───────────────────────────────────────────────────────
   Only transform + opacity. No width/height/margin — those cause reflow.
   All animations target .br-emoji or the button itself, never layout props.
   ────────────────────────────────────────────────────────────────────────── */

/* Pop: first-click feedback — bouncy scale */
@keyframes br-pop {
	0%   { transform: scale(1); }
	35%  { transform: scale(1.28); }
	65%  { transform: scale(0.96); }
	100% { transform: scale(1); }
}

/* Shake: already-reacted or server error */
@keyframes br-shake {
	0%,  100% { transform: translateX(0); }
	20%        { transform: translateX(-4px); }
	40%        { transform: translateX(4px); }
	60%        { transform: translateX(-3px); }
	80%        { transform: translateX(3px); }
}

/* Pulse glow: plays once when is-reacted is applied */
@keyframes br-pulse {
	0%,  100% { box-shadow: 0 0 0 0   var(--br-border-reacted); }
	50%        { box-shadow: 0 0 0 3px var(--br-border-reacted); }
}

/* Applied by triggerClass() — removed automatically on animationend */
.br-btn.is-pop .br-emoji {
	animation: br-pop 0.32s var(--br-ease) forwards;
}

.br-btn.is-shake {
	animation: br-shake 0.38s ease forwards;
}

/* One-shot pulse when the reacted state is first applied */
.br-btn.is-reacted {
	animation: br-pulse 0.5s ease 0.1s 1 forwards;
}

/* Pop takes priority when both classes briefly coexist at commit moment */
.br-btn.is-reacted.is-pop .br-emoji {
	animation: br-pop 0.32s var(--br-ease) forwards;
}

/* ── Reduced motion ─────────────────────────────────────────────────────────
   Disables ALL animations and transitions for users who prefer it.
   Visual state changes (color, border, background) still apply.
   ────────────────────────────────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
	.br-btn,
	.br-btn.is-pop .br-emoji,
	.br-btn.is-shake,
	.br-btn.is-reacted,
	.br-btn.is-cancelled,
	.br-btn.is-pending::after {
		animation:  none !important;
		transition: none !important;
	}
}

/* ── No-JS fallback ─────────────────────────────────────────────────────────
   Without JS the buttons are visible and counts are readable.
   The :disabled style prevents interaction cues on non-interactive buttons.
   (class-br-render.php can add aria-disabled="true" in a future enhancement)
   ────────────────────────────────────────────────────────────────────────── */
.br-btn[aria-disabled="true"] {
	cursor:  default;
	pointer-events: none;
	opacity: 0.7;
}

/* ── Responsive ─────────────────────────────────────────────────────────────*/
@media (max-width: 480px) {
	.br {
		gap: 5px;
	}

	.br-btn {
		--br-padding:    0.4em 0.75em;
		--br-font-size:  0.8rem;
	}
}
