/* ==========================================================================
   OpsPulse — Rio, the site assistant widget
   --------------------------------------------------------------------------
   Kept in its own file rather than appended to styles.css on purpose:
   styles.css is the shared design system and is currently byte-identical to
   the copy on the other branch. Keeping the widget separate means the two
   can still be diffed cleanly.

   Every colour, radius, shadow and easing below comes from the tokens already
   declared in styles.css :root — the widget is a new component, not a new
   visual language. What it does with them is louder than the rest of the site
   on purpose: this is the one element that has to earn a click from someone
   who was not looking for it, so it carries the brand gradient in motion
   (a slow conic aurora, a sheen across the pill, a live hairline along the
   panel) where the page itself stays still.

   Everything decorative here is a pseudo-element with `pointer-events: none`,
   so none of it can intercept a click or sit over a :focus-visible outline.
   Every animation introduced below has a matching line in the reduced-motion
   block at the end of the file — add to both or neither.
   ========================================================================== */

.cw {
  position: fixed;
  right: 22px;
  bottom: 22px;
  z-index: 900;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 12px;
  font-family: inherit;
}

.cw-sr {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ---------- Launcher ---------- */
.cw-launch {
  order: 2;                       /* stays below the panel however the DOM sits */
  position: relative;             /* anchors the aurora and the ping */
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 12px 18px 12px 14px;
  border: 0;
  border-radius: 100px;
  color: #04120c;
  font: inherit;
  font-size: 0.88rem;
  font-weight: 700;
  letter-spacing: 0.01em;
  cursor: pointer;
  box-shadow:
    0 16px 40px -12px rgba(52, 211, 153, 0.6),
    inset 0 1px 0 rgba(255, 255, 255, 0.4);
  transition: transform 0.2s var(--ease), box-shadow 0.25s var(--ease);

  /* Two layers: a narrow highlight that sweeps across, over the brand
     gradient. Done with background-position rather than an overflow-clipped
     child so the pill never needs `overflow: hidden` — which would amputate
     the ping dot sitting outside its top-right corner. */
  background:
    linear-gradient(100deg, transparent 34%, rgba(255, 255, 255, 0.55) 46%, transparent 58%),
    var(--grad);
  background-size: 250% 100%, 100% 100%;
  background-repeat: no-repeat;
  background-position: 250% 0, 0 0;
  animation: cw-sheen 6.5s var(--ease) infinite;
}

/* The halo under the pill. Deliberately NOT the rotating conic used on the
   avatar: that trick only works on a square box. Spinning a 164×59 pill turns
   it into a 59×164 one twice a cycle, which reads as a pulsing blob rather
   than a glow. So this one is a static gradient that brightens on hover —
   which also keeps an 11px blur off the compositor's per-frame budget on a
   landing page nobody has interacted with yet.

   z-index: -1 with no stacking context on .cw-launch itself puts it behind
   the button but still inside .cw, so it glows under the pill instead of
   washing over its gradient. */
.cw-launch::before {
  content: "";
  position: absolute;
  inset: -7px;
  z-index: -1;
  border-radius: 100px;
  background: linear-gradient(120deg, #22d3ee, #34d399 55%, #a3e635);
  filter: blur(11px);
  opacity: 0.5;
  pointer-events: none;
  transition: opacity 0.25s var(--ease);
}

.cw-launch:hover { transform: translateY(-2px); box-shadow: 0 22px 52px -12px rgba(52, 211, 153, 0.75), inset 0 1px 0 rgba(255, 255, 255, 0.45); }
.cw-launch:hover::before,
.cw-launch:focus-visible::before { opacity: 0.9; }
.cw-launch:active { transform: translateY(0) scale(0.985); }
.cw-launch:focus-visible { outline: 2px solid var(--cyan); outline-offset: 4px; }

.cw-launch-ico svg,
.cw-launch-x svg { width: 19px; height: 19px; display: block; }
.cw-launch-ico, .cw-launch-x { display: flex; }
.cw-launch-x { display: none; }

/* Attention dot. Shown once, until the panel has been opened for the first
   time — the JS drops `cw-new` for good at that point, because a badge that
   came back would be claiming an unread message and nothing here ever
   arrives unprompted. */
.cw-ping {
  position: absolute;
  top: -3px; right: -3px;
  width: 11px; height: 11px;
  border-radius: 50%;
  background: #a3e635;
  border: 2px solid var(--bg);
  pointer-events: none;
}
.cw-ping::after {
  content: "";
  position: absolute;
  inset: -2px;
  border-radius: 50%;
  border: 2px solid rgba(163, 230, 53, 0.75);
  animation: cw-ripple 2.2s var(--ease) infinite;
}
.cw:not(.cw-new) .cw-ping,
.cw-open .cw-ping { display: none; }

/* Open state: the launcher collapses to a round close button, so the panel
   is never fighting a wide pill for space on a narrow screen. */
.cw-open .cw-launch { padding: 13px; }
.cw-open .cw-launch-ico,
.cw-open .cw-launch-label { display: none; }
.cw-open .cw-launch-x { display: flex; }

/* ---------- Panel ---------- */
.cw-panel {
  order: 1;
  position: relative;
  width: 380px;
  max-width: calc(100vw - 32px);
  height: 540px;
  max-height: calc(100vh - 130px);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--panel);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  box-shadow:
    var(--shadow),
    0 0 0 1px rgba(52, 211, 153, 0.16),
    0 34px 90px -22px rgba(34, 211, 238, 0.4);
  animation: cw-in 0.34s var(--ease) both;
  transform-origin: bottom right;
}
.cw-panel[hidden] { display: none; }

/* Frosted glass, but only where it is actually supported: at 0.78 alpha
   without a backdrop filter the panel would just be a see-through box with
   the page showing through the text. */
@supports ((backdrop-filter: blur(2px)) or (-webkit-backdrop-filter: blur(2px))) {
  .cw-panel {
    background: rgba(14, 20, 37, 0.78);
    -webkit-backdrop-filter: blur(22px) saturate(150%);
    backdrop-filter: blur(22px) saturate(150%);
  }
}

/* A live hairline along the top edge — the panel's pulse, and the cheapest
   possible signal that the thing is running rather than a static popover.
   Clipped to the panel's rounded corners by its `overflow: hidden`. */
.cw-panel::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 2px;
  z-index: 3;
  pointer-events: none;
  background: linear-gradient(90deg, transparent 0%, var(--cyan) 25%, var(--emerald) 50%, #a3e635 70%, transparent 100%);
  background-size: 220% 100%;
  background-repeat: no-repeat;   /* one comet crossing, not a tiled row of them */
  animation: cw-drift 5.5s linear infinite;
}

/* The `to` keyframe deliberately does not name `filter`. `filter: blur(0)` is
   still a filter, and with `animation-fill-mode: both` it would stay on the
   panel forever — and an element with its own filter is exactly the case
   where `backdrop-filter` silently stops frosting anything. Leaving it out
   lets the blur interpolate back toward the underlying `none`. */
@keyframes cw-in {
  from { opacity: 0; transform: translateY(20px) scale(0.94); filter: blur(6px); }
  to   { opacity: 1; transform: none; }
}

/* ---------- Head ---------- */
.cw-head {
  position: relative;
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 15px 14px 14px 16px;
  border-bottom: 1px solid var(--line);
  flex: 0 0 auto;
  /* Two off-centre washes rather than one flat tint, so the header reads as
     lit from behind by the same gradient the mark spins. */
  background:
    radial-gradient(120% 160% at 12% 0%, rgba(34, 211, 238, 0.16), transparent 60%),
    radial-gradient(90% 140% at 78% 10%, rgba(139, 92, 246, 0.13), transparent 62%),
    linear-gradient(180deg, rgba(52, 211, 153, 0.07), transparent);
}

/* The avatar is a rotating conic disc with the mark punched over it in ink.
   `isolation: isolate` is what makes this work: it gives the avatar its own
   stacking context so the two negative-z pseudos stay inside the 34px box
   (glow behind disc, disc behind glyph) instead of falling behind the
   panel's opaque background and vanishing. */
.cw-avatar {
  position: relative;
  isolation: isolate;
  display: grid;
  place-items: center;
  width: 34px; height: 34px;
  flex: 0 0 auto;
  border-radius: 11px;
  background: transparent;
  color: #04120c;
}
.cw-avatar::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  background: conic-gradient(from 0deg, #22d3ee, #34d399, #a3e635, #34d399, #22d3ee);
  pointer-events: none;
  animation: cw-spin 8s linear infinite;
}
.cw-avatar::after {
  content: "";
  position: absolute;
  inset: -4px;
  z-index: -2;
  border-radius: 14px;
  background: var(--grad);
  filter: blur(8px);
  opacity: 0.5;
  pointer-events: none;
}
.cw-avatar svg { width: 19px; height: 19px; }

.cw-head-txt { min-width: 0; flex: 1; }
.cw-head-txt strong {
  display: inline-block;
  font-size: 1rem; font-weight: 750; letter-spacing: 0.005em;
  /* The name carries the brand gradient itself now that the "AI" chip is
     gone — with the assistant called Rio, name + chip would have read back
     as the old "RioAI" the rename removed. */
  background: var(--grad);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.cw-head-txt small {
  display: flex; align-items: center; gap: 6px; margin-top: 2px;
  font-size: 0.7rem; line-height: 1.35; color: var(--text-dim);
}

/* Live status dot with a soft pulse, so the header reads as "here and
   listening". Falls still under reduced-motion. */
.cw-dot {
  width: 7px; height: 7px; border-radius: 50%; flex: 0 0 auto;
  background: #34d399;
  box-shadow: 0 0 0 0 rgba(52, 211, 153, 0.6);
  animation: cw-pulse 2.4s var(--ease) infinite;
}
@keyframes cw-pulse {
  0%   { box-shadow: 0 0 0 0 rgba(52, 211, 153, 0.55); }
  70%  { box-shadow: 0 0 0 6px rgba(52, 211, 153, 0); }
  100% { box-shadow: 0 0 0 0 rgba(52, 211, 153, 0); }
}

.cw-close {
  flex: 0 0 auto;
  display: grid; place-items: center;
  width: 30px; height: 30px;
  border: 1px solid var(--line);
  border-radius: 9px;
  background: rgba(255, 255, 255, 0.03);
  color: var(--text-dim);
  cursor: pointer;
  transition: color 0.2s, background 0.2s, border-color 0.2s, transform 0.2s var(--ease);
}
.cw-close svg { width: 15px; height: 15px; }
/* Scale, not rotate: the glyph is two crossing diagonals, so rotating it 90°
   maps each stroke onto the other and nothing appears to happen. */
.cw-close:hover {
  color: var(--text);
  background: rgba(255, 255, 255, 0.08);
  border-color: var(--line-strong);
  transform: scale(1.09);
}
.cw-close:focus-visible { outline: 2px solid var(--cyan); outline-offset: 2px; }

/* ---------- Log ---------- */
.cw-log {
  flex: 1 1 auto;
  overflow-y: auto;
  padding: 16px 14px 6px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  scrollbar-width: thin;
  scrollbar-color: rgba(52, 211, 153, 0.35) transparent;
  /* Messages dissolve into the header instead of colliding with it as they
     scroll under the hairline. */
  -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 16px);
  mask-image: linear-gradient(180deg, transparent 0, #000 16px);
}
.cw-log::-webkit-scrollbar { width: 8px; }
.cw-log::-webkit-scrollbar-thumb {
  background: linear-gradient(180deg, rgba(34, 211, 238, 0.45), rgba(52, 211, 153, 0.45));
  border-radius: 100px;
}

.cw-msg {
  display: flex;
  align-items: flex-end;
  gap: 8px;
  animation: cw-msg-in 0.3s var(--ease) both;
}
.cw-msg.cw-me { justify-content: flex-end; }

/* The little shield next to each Rio turn. Sits at the bottom of the bubble
   so a tall multi-paragraph answer still anchors it at the corner. Same
   isolated-stacking-context trick as the header avatar, at 26px. */
.cw-msg-ava {
  position: relative;
  isolation: isolate;
  flex: 0 0 auto;
  display: grid; place-items: center;
  width: 26px; height: 26px;
  margin-bottom: 1px;
  border-radius: 9px;
  color: #04120c;
}
.cw-msg-ava::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  background: conic-gradient(from 0deg, #22d3ee, #34d399, #a3e635, #34d399, #22d3ee);
  pointer-events: none;
}
.cw-msg-ava svg { width: 15px; height: 15px; }

.cw-bubble {
  max-width: 84%;
  padding: 11px 14px;
  border-radius: 15px;
  font-size: 0.855rem;
  line-height: 1.6;
  color: var(--text-soft);
  background: var(--panel-2);
  border: 1px solid var(--line);
}
.cw-bubble p { margin: 0 0 8px; }
.cw-bubble p:last-child { margin-bottom: 0; }
.cw-bubble strong { color: var(--text); font-weight: 650; }
.cw-bubble em { color: var(--text); font-style: italic; }

/* Bulleted answers — a real list with a gradient tick marker, so the signal
   sources and plan tiers read cleanly instead of as run-on paragraphs. */
.cw-list { margin: 2px 0 8px; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 5px; }
.cw-list:last-child { margin-bottom: 0; }
.cw-list li { position: relative; padding-left: 16px; }
.cw-list li::before {
  content: ""; position: absolute; left: 2px; top: 0.62em;
  width: 5px; height: 5px; border-radius: 50%;
  background: var(--grad);
}

.cw-bot .cw-bubble {
  border-bottom-left-radius: 5px;
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0.015)),
    var(--panel-2);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05);
}
.cw-me .cw-bubble {
  border-bottom-right-radius: 5px;
  background: linear-gradient(135deg, rgba(34, 211, 238, 0.18), rgba(52, 211, 153, 0.14));
  border-color: rgba(52, 211, 153, 0.32);
  color: var(--text);
  box-shadow: 0 6px 18px -10px rgba(34, 211, 238, 0.6);
}

/* ---------- Typing indicator ---------- */
.cw-typing { display: inline-flex; gap: 5px; padding: 3px 0; }
.cw-typing i {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--grad);
  animation: cw-blink 1.1s infinite both;
}
.cw-typing i:nth-child(2) { animation-delay: 0.16s; }
.cw-typing i:nth-child(3) { animation-delay: 0.32s; }
@keyframes cw-blink {
  0%, 70%, 100% { opacity: 0.28; transform: translateY(0) scale(0.85); }
  35%           { opacity: 1;    transform: translateY(-4px) scale(1); }
}

/* ---------- Suggested questions ---------- */
.cw-chips {
  flex: 0 0 auto;
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
  padding: 10px 14px 12px;
}
/* The rail is offered once, with Rio's opening line, and emptied for good as
   soon as the visitor asks anything. `:empty` is what actually removes it from
   the column — without this it would keep claiming its 22px of padding on a
   phone for the rest of the conversation, which is the height the answer
   itself needs. */
.cw-chips:empty { display: none; }
.cw-chip {
  position: relative;
  overflow: hidden;               /* clips the hover shine to the pill */
  padding: 7px 12px;
  border-radius: 100px;
  border: 1px solid var(--line-strong);
  background: rgba(255, 255, 255, 0.03);
  color: var(--text-soft);
  font: inherit;
  font-size: 0.765rem;
  font-weight: 500;
  line-height: 1.2;
  cursor: pointer;
  transition: color 0.18s, background 0.18s, border-color 0.18s, transform 0.18s var(--ease), box-shadow 0.18s;
  /* The chips arrive with the opening line rather than appearing to have been
     there all along. Staggered by position. */
  animation: cw-chip-in 0.26s var(--ease) both;
}
.cw-chip:nth-child(2) { animation-delay: 0.05s; }
.cw-chip:nth-child(3) { animation-delay: 0.1s; }
.cw-chip:nth-child(4) { animation-delay: 0.15s; }
.cw-chip::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(100deg, transparent 30%, rgba(255, 255, 255, 0.22) 48%, transparent 66%);
  background-size: 250% 100%;
  background-position: 250% 0;
  background-repeat: no-repeat;
}
.cw-chip:hover {
  color: var(--text);
  background: rgba(52, 211, 153, 0.12);
  border-color: rgba(52, 211, 153, 0.45);
  transform: translateY(-1px);
  box-shadow: 0 8px 20px -12px rgba(52, 211, 153, 0.9);
}
.cw-chip:hover::after { animation: cw-shine 0.65s var(--ease) 1; }
.cw-chip:focus-visible { outline: 2px solid var(--cyan); outline-offset: 2px; }

/* ---------- Composer ---------- */
.cw-input {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 11px 12px;
  border-top: 1px solid var(--line);
  background: rgba(0, 0, 0, 0.28);
}
.cw-input input {
  flex: 1;
  min-width: 0;
  padding: 10px 14px;
  border-radius: 100px;
  border: 1px solid var(--line-strong);
  background: var(--bg-2);
  color: var(--text);
  font: inherit;
  font-size: 0.85rem;
  transition: border-color 0.2s, box-shadow 0.2s, background 0.2s;
}
.cw-input input::placeholder { color: var(--text-dim); }
.cw-input input:focus {
  outline: none;
  background: var(--panel);
  border-color: rgba(52, 211, 153, 0.55);
  box-shadow: 0 0 0 3px rgba(52, 211, 153, 0.14), 0 0 22px -6px rgba(34, 211, 238, 0.5);
}

.cw-send {
  position: relative;
  flex: 0 0 auto;
  display: grid; place-items: center;
  width: 38px; height: 38px;
  border: 0;
  border-radius: 50%;
  background: var(--grad);
  color: #04120c;
  cursor: pointer;
  box-shadow: 0 8px 20px -10px rgba(52, 211, 153, 0.9);
  transition: transform 0.18s var(--ease), box-shadow 0.2s;
}
.cw-send svg { width: 18px; height: 18px; transition: transform 0.18s var(--ease); }
.cw-send:hover { transform: scale(1.07); box-shadow: 0 12px 26px -8px rgba(52, 211, 153, 0.8); }
.cw-send:hover svg { transform: translateX(2px); }
.cw-send:active { transform: scale(0.97); }
.cw-send:focus-visible { outline: 2px solid var(--cyan); outline-offset: 3px; }

/* ---------- Keyframes ---------- */
@keyframes cw-spin   { to { transform: rotate(360deg); } }
/* Both endpoints sit fully off the pill, so the jump back at the loop
   boundary is invisible. An intermediate stop at 100% would instead drag the
   highlight backwards across the pill on every cycle. */
@keyframes cw-sheen  {
  0%, 55%   { background-position: 250% 0, 0 0; }
  90%, 100% { background-position: -150% 0, 0 0; }
}
@keyframes cw-shine  { from { background-position: 250% 0; } to { background-position: -150% 0; } }
@keyframes cw-drift  { from { background-position: 220% 0; } to { background-position: -120% 0; } }
@keyframes cw-ripple {
  0%   { transform: scale(1);   opacity: 0.9; }
  70%  { transform: scale(2.4); opacity: 0; }
  100% { transform: scale(2.4); opacity: 0; }
}
@keyframes cw-msg-in  { from { opacity: 0; transform: translateY(9px) scale(0.985); } to { opacity: 1; transform: none; } }
@keyframes cw-chip-in { from { opacity: 0; transform: translateY(5px); } to { opacity: 1; transform: none; } }

/* ---------- Small screens ---------- */
@media (max-width: 520px) {
  .cw { right: 14px; bottom: 14px; left: 14px; align-items: stretch; }
  .cw-launch { align-self: flex-end; }
  .cw-panel { width: auto; height: min(560px, calc(100vh - 110px)); }
  .cw-launch-label { display: none; }
  .cw-launch { padding: 13px; border-radius: 50%; }
}

/* ---------- Reduced motion ----------
   Every keyframe declared above is switched off here. The widget keeps its
   colour and depth and loses only the movement, so nothing that carries
   meaning (the live dot, the ping, the typing indicator) disappears — it
   just stops moving. */
@media (prefers-reduced-motion: reduce) {
  .cw-panel { animation: none; }
  .cw-launch, .cw-chip, .cw-send, .cw-close, .cw-input input { transition: none; }
  .cw-launch { animation: none; background-position: 250% 0, 0 0; }
  .cw-avatar::before { animation: none; }
  .cw-panel::before { animation: none; background-position: 50% 0; }
  .cw-chip, .cw-msg { animation: none; }
  .cw-chip:hover::after { animation: none; }
  .cw-typing i { animation: none; opacity: 0.5; transform: none; }
  .cw-dot { animation: none; }
  .cw-ping::after { animation: none; }
  .cw-close:hover { transform: none; }
}
