/* ═══════════════════════════════════════════════════════════════════
   psfx-mood.css — mood-reactive glow for the composer and reply bubbles.

   Two performance rules, both from the research:
     1. Register the colour vars with @property so the COLOUR interpolates
        instead of snapping. Unregistered custom props are opaque strings.
     2. Never animate box-shadow / filter. The glow sits on a pseudo-element
        and only its OPACITY animates, which stays on the compositor.
   ═══════════════════════════════════════════════════════════════════ */

@property --fx-mood-glow {
  syntax: '<color>';
  inherits: true;
  initial-value: rgb(255, 45, 120);
}
@property --fx-mood-edge {
  syntax: '<color>';
  inherits: true;
  initial-value: rgb(255, 90, 160);
}
@property --fx-mood-strength {
  syntax: '<number>';
  inherits: true;
  initial-value: 0.5;
}

/* the whole scene eases between moods — one transition, everything follows */
#pscRoot.fx-mood-on {
  transition: --fx-mood-glow 700ms ease, --fx-mood-edge 700ms ease,
              --fx-mood-strength 700ms ease;
}

/* ── COMPOSER ─────────────────────────────────────────────────────── */
#pscRoot.fx-mood-on .chat-input-wrap {
  position: relative;
  border-color: rgba(var(--fx-mood-rgb, 255,45,120), .55);
}
/* glow layer — opacity is the only animated property.
   inset is NEGATIVE and overflow must stay visible: the halo lives OUTSIDE the
   box, so an opaque composer background can hide the part behind it without
   hiding the glow itself. An ancestor with overflow:hidden would clip it. */
#pscRoot.fx-mood-on .chat-input-wrap { overflow: visible; }
#pscRoot.fx-mood-on .chat-input-wrap::after {
  content: ''; position: absolute; inset: -2px; border-radius: inherit;
  pointer-events: none; z-index: -1;
  box-shadow: 0 0 18px 2px var(--fx-mood-glow), 0 0 42px 6px var(--fx-mood-glow);
  opacity: calc(var(--fx-mood-strength) * .34);
  transition: opacity 700ms ease;
}
/* typing raises the glow — pure CSS, inherits the mood colour automatically */
#pscRoot.fx-mood-on .chat-input-wrap:focus-within::after {
  opacity: calc(var(--fx-mood-strength) * .62);
}
#pscRoot.fx-mood-on .chat-textarea { caret-color: var(--fx-mood-edge); }
#pscRoot.fx-mood-on .chat-send {
  background: linear-gradient(135deg, var(--fx-mood-glow), var(--fx-mood-edge));
}

/* ── REPLY BUBBLES ────────────────────────────────────────────────── */
/* the newest reply carries the mood on its edge; older ones stay neutral so
   the eye is drawn to the live moment rather than the whole transcript */
#pscRoot.fx-mood-on .chat-msg.bot:last-of-type .bubble {
  position: relative;
  border-color: rgba(var(--fx-mood-rgb, 255,45,120), .42);
}
#pscRoot.fx-mood-on .chat-msg.bot:last-of-type .bubble { overflow: visible; }
#pscRoot.fx-mood-on .chat-msg.bot:last-of-type .bubble::after {
  content: ''; position: absolute; inset: -2px; border-radius: inherit;
  pointer-events: none; z-index: -1;
  box-shadow: 0 0 16px 1px var(--fx-mood-glow), 0 0 38px 5px var(--fx-mood-glow);
  opacity: calc(var(--fx-mood-strength) * .22);
  transition: opacity 700ms ease;
}

/* ── HOT MOODS BREATHE ────────────────────────────────────────────── */
/* only the strongest moods (arousal, rage, terror) get a slow pulse — a 3.2s
   cycle reads as ambient, not urgent. opacity-only, so still compositor-side. */
#pscRoot.fx-mood-on.fx-mood-hot .chat-input-wrap::after {
  animation: fxMoodBreathe 3.2s ease-in-out infinite;
}
@keyframes fxMoodBreathe {
  0%, 100% { opacity: calc(var(--fx-mood-strength) * .30); }
  50%      { opacity: calc(var(--fx-mood-strength) * .60); }
}

/* ── STATUS CHROME picks up the mood too, for cohesion ────────────── */
#pscRoot.fx-mood-on .psc-statusbar.has-state .css-bar span {
  background: linear-gradient(90deg, var(--fx-mood-glow), var(--fx-mood-edge));
}

/* ── RESTRAINT ────────────────────────────────────────────────────── */
/* Calm mode / reduced motion: keep the COLOUR (it carries meaning) but drop
   the bloom and all motion. Colour is information; pulsing is decoration. */
@media (prefers-reduced-motion: reduce) {
  #pscRoot.fx-mood-on { transition: none; }
  #pscRoot.fx-mood-on.fx-mood-hot .chat-input-wrap::after { animation: none; }
  #pscRoot.fx-mood-on .chat-input-wrap::after,
  #pscRoot.fx-mood-on .chat-msg.bot:last-of-type .bubble::after { transition: none; }
}
body.psfx-calm #pscRoot.fx-mood-on.fx-mood-hot .chat-input-wrap::after { animation: none; }
body.psfx-calm #pscRoot.fx-mood-on .chat-msg.bot:last-of-type .bubble::after { opacity: 0; }

/* Fallback for engines without @property: the colours still apply, they just
   snap instead of interpolating. Nothing breaks. */
@supports not (background: paint(x)) {
  #pscRoot.fx-mood-on { transition: none; }
}