/* ============================================================================
   رِماية — «راكان» floating agent character (public pages)
   ----------------------------------------------------------------------------
   One floater, shared by every public page (index · faq · plans · privacy ·
   terms). It is the only entry point to `/call`, where the visitor talks to
   Rakan live. Behaviour lives in `js/agent-float.js`; this file owns the look.
   The character's name is never written here: the chip and its aria-label are
   composed at runtime from `/api/public/agent/status`.

   Rules it answers to (AGENTS.md §2, the brief):
   - bottom corner on the INLINE-END side (bottom-left in RTL), 16px off the
     edges plus the device safe area, above everything but the skip link.
   - 72px on desktop, 52px on a phone (< 760px), on a soft glowing round base;
     the Rimaya robot sits on that base once it has loaded, and a clean gradient
     orb with a small robot face stands in until then (and forever if WebGL is
     missing).
   - the speech chip is a label, not a sentence: two words and a live dot. On a
     phone it sits compactly above the avatar for four seconds after the first
     screen has settled, so the hero still has a visible, labelled way in — and
     it never lands on the hero's own call to action.
   - reading downward tucks it away for a moment (.is-tucked, owned by
     js/agent-float.js): it is never in the way of the copy, and it is never
     hidden from a visitor who is on it with the keyboard.
   - motion is capped and fully honoured by `prefers-reduced-motion`.

   Colours come from the page tokens where they exist, with the identity's own
   literals as the fallback, so the file also works when it is the only
   stylesheet linked.
   ========================================================================== */

:root {
  --af-size: 72px;
  --af-electric: var(--electric, #5c17fd);
  --af-violet: var(--violet, #bb50f8);
  --af-ease: var(--ease, cubic-bezier(0.22, 1, 0.36, 1));
}

@media (max-width: 759.98px) {
  :root {
    --af-size: 52px;
  }

  /* still the inline-end corner (bottom-left in RTL), now 16px off both edges
     and safe-area aware on the bottom one */
  .agent-float {
    inset-block-end: 16px;
    inset-block-end: max(16px, env(safe-area-inset-bottom, 0px));
    inset-inline-end: 16px;
  }
}

/* ------------------------------------------------------------------ floater -- */
.agent-float {
  position: fixed;
  z-index: 60;
  /* Plain value first: a browser without max()/env() still gets the 16px corner
     rather than an auto-positioned floater. Then the safe area is added — the
     larger of the two horizontal insets, because the inline-end corner is the
     left edge in RTL and the right edge in LTR. */
  inset-block-end: 16px;
  inset-block-end: calc(16px + max(env(safe-area-inset-bottom, 0px), 0px));
  inset-inline-end: 16px;
  inset-inline-end: calc(16px + max(env(safe-area-inset-right, 0px), env(safe-area-inset-left, 0px)));
  opacity: 0;
  transform: translateY(12px) scale(0.9);
  transition: opacity 420ms var(--af-ease), transform 480ms var(--af-ease);
}

.agent-float[hidden] {
  display: none;
}

.agent-float.is-in {
  opacity: 1;
  transform: none;
}

/* While the mobile menu is open the floater steps aside: the panel is taller
   than the gap under the header and would otherwise sit on top of it. */
.agent-float.is-away {
  opacity: 0;
  transform: translateY(14px) scale(0.92);
  pointer-events: none;
}

/* Reading downward tucks it out of the way: a short slide down plus a fade,
   240ms. Scrolling up, a 1.2s pause, either end of the page, or a focus brings
   it back (the return rides the entrance transition above). `pointer-events:
   none` is load-bearing: a merely faded-out floater would still swallow the
   taps meant for the content underneath it. */
.agent-float.is-tucked {
  opacity: 0;
  transform: translateY(16px);
  pointer-events: none;
  transition: opacity 240ms ease, transform 240ms var(--af-ease);
}

/* A phone's first screen already has the hero's own «تكلّم مع راكان», so the
   floater holds back until that hero leaves the viewport: one entry point, never
   two, and no robot standing on the hero's product tiles. Focus wins. */
@media (max-width: 759.98px) {
  .agent-float.is-hero {
    opacity: 0;
    transform: translateY(16px);
    pointer-events: none;
  }
}

.agent-float__btn {
  position: relative;
  display: block;
  width: var(--af-size);
  height: var(--af-size);
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: none;
  color: #fff;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

.agent-float__btn:focus {
  outline: none;
}

.agent-float__btn:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 3px;
}

/* the soft lit base under the character */
.agent-float__base {
  position: absolute;
  inset: -34%;
  border-radius: 50%;
  background: radial-gradient(
    circle at 50% 56%,
    rgba(187, 80, 248, 0.4),
    rgba(92, 23, 253, 0.16) 54%,
    rgba(92, 23, 253, 0) 72%
  );
  filter: blur(7px);
  pointer-events: none;
  animation: af-breathe 6s ease-in-out infinite;
}

/* the stand-in avatar: gradient orb + a small robot face, no WebGL required */
.agent-float__orb {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background:
    radial-gradient(circle at 34% 26%, rgba(255, 255, 255, 0.34), rgba(255, 255, 255, 0) 46%),
    linear-gradient(150deg, var(--af-electric), var(--af-violet) 78%);
  box-shadow:
    0 0 0 1px rgba(187, 80, 248, 0.42),
    0 1px 0 rgba(255, 255, 255, 0.32) inset,
    0 20px 38px -20px rgba(92, 23, 253, 0.95);
  transition: opacity 340ms var(--af-ease), transform 340ms var(--af-ease);
  pointer-events: none;
}

.agent-float__face {
  display: block;
  width: 62%;
  height: 62%;
  color: #fff;
}

/* the robot's own canvas takes over once it is mounted */
.agent-float .agent-float__host {
  position: absolute;
  /* physical centring on purpose: the box is a square and `translate(-50%)`
     is not direction-aware, so a logical inset would pull it off-centre in RTL */
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  opacity: 0;
  transition: opacity 420ms var(--af-ease);
  pointer-events: none;
}

.agent-float.is-live .agent-float__host {
  opacity: 1;
  /* Once the robot is mounted it bobs gently on the base: a short lift roughly
     every 8s, so the corner reads as alive without ever nagging. The animation
     carries the centring translate with it, and it pauses while the visitor is
     engaged with the button (hover/focus) so the robot is still when they reach
     for it. Reduced motion turns it off entirely (see the guard at the end). */
  animation: af-bob 8s ease-in-out infinite;
}

.agent-float__btn:hover .agent-float__host,
.agent-float__btn:focus-visible .agent-float__host {
  animation-play-state: paused;
}

.agent-float.is-live .agent-float__orb {
  opacity: 0;
  transform: scale(0.86);
}

/* ------------------------------------------------------------- speech chip -- */
.agent-float__bubble {
  position: absolute;
  inset-block-start: 50%;
  inset-inline-end: calc(100% + 18px);
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 10px 15px;
  border: 1px solid rgba(255, 255, 255, 0.72);
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.92);
  -webkit-backdrop-filter: blur(14px) saturate(150%);
  backdrop-filter: blur(14px) saturate(150%);
  color: var(--ink-0, #08060d);
  font-family: var(--font, system-ui, "Segoe UI", Tahoma, sans-serif);
  font-size: 13px;
  font-weight: 600;
  line-height: 1.35;
  /* An absolutely-positioned box shrinks to fit its containing block, which is
     the button's own 72px box — so the chip would wrap into a column. `max-content`
     asks for one line, and the cap lets a long exhausted label (the creator's
     WhatsApp hand-off) wrap only when it truly has to. */
  width: max-content;
  max-width: min(74vw, 320px);
  white-space: normal;
  text-align: start;
  box-shadow:
    0 18px 40px -22px rgba(0, 0, 0, 0.7),
    0 1px 0 rgba(255, 255, 255, 0.6) inset;
  opacity: 0;
  transform: translateY(-50%) scale(0.94);
  transition:
    inset-inline-end 320ms var(--af-ease),
    opacity 240ms ease,
    transform 320ms var(--af-ease);
  pointer-events: none;
}

.agent-float__words {
  font-weight: 600;
}

.agent-float__dot {
  flex: none;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: #22c55e;
  box-shadow:
    0 0 0 3px rgba(34, 197, 94, 0.18),
    0 0 10px 1px rgba(34, 197, 94, 0.7);
  animation: af-live 2.4s ease-in-out infinite;
}

.agent-float.is-bubble .agent-float__bubble,
.agent-float__btn:hover .agent-float__bubble,
.agent-float__btn:focus-visible .agent-float__bubble {
  inset-inline-end: calc(100% + 12px);
  opacity: 1;
  transform: translateY(-50%) scale(1);
}

/* A phone: the avatar stays at the corner and the chip sits just above it, one
   compact line, so the first screen still has a labelled way into the call
   without the chip lying across the hero copy. */
@media (max-width: 759.98px) {
  .agent-float__bubble {
    inset-block-start: auto;
    inset-block-end: calc(100% + 10px);
    inset-inline-end: 0;
    max-width: min(70vw, 260px);
    padding: 9px 13px;
    font-size: 12.5px;
    transform: translateY(4px) scale(0.96);
    pointer-events: auto;
  }
  .agent-float.is-bubble .agent-float__bubble,
  .agent-float__btn:hover .agent-float__bubble,
  .agent-float__btn:focus-visible .agent-float__bubble {
    inset-inline-end: 0;
    transform: none;
  }
}

/* ------------------------------------------------------- launch transition -- */
/* One motion: the floater grows into a circle that fills the screen in brand
   purple, and the page it covers is `/call`. */
.agent-float__launch {
  position: fixed;
  z-index: 90;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 44%, #7a2bff, var(--af-electric) 58%, #331761);
  transform: translate(-50%, -50%) scale(1);
  opacity: 1;
  pointer-events: none;
  will-change: transform;
  transition: transform 340ms cubic-bezier(0.4, 0, 0.2, 1);
}

.agent-float.is-launching {
  opacity: 0;
  transform: none;
  transition: opacity 200ms ease 140ms;
}

/* The floater is fixed, so it must not hide the footer's last line: the pages
   reserve its height at the very bottom while it is on screen. */
.has-agent-float .foot {
  padding-block-end: calc(var(--af-size) + 34px);
}

/* ------------------------------------------------------------------ motion -- */
@keyframes af-breathe {
  0%,
  100% {
    opacity: 0.85;
    transform: scale(1);
  }
  50% {
    opacity: 1;
    transform: scale(1.08);
  }
}

@keyframes af-live {
  0%,
  100% {
    opacity: 1;
    transform: scale(1);
  }
  50% {
    opacity: 0.4;
    transform: scale(0.7);
  }
}

/* the idle bob: still for most of the cycle, one soft lift near the end */
@keyframes af-bob {
  0%,
  76%,
  100% {
    transform: translate(-50%, -50%);
  }
  82% {
    transform: translate(-50%, calc(-50% - 6px));
  }
  88% {
    transform: translate(-50%, calc(-50% + 3px));
  }
  94% {
    transform: translate(-50%, calc(-50% - 2px));
  }
}

@media (prefers-reduced-motion: reduce) {
  .agent-float,
  .agent-float__orb,
  .agent-float__host,
  .agent-float__bubble,
  .agent-float__launch {
    transition-duration: 1ms !important;
  }

  .agent-float {
    transform: none;
  }

  /* tucked is a fade and nothing else for a visitor who asked motion to stop;
     the 1ms durations above already make that fade instant */
  .agent-float.is-tucked {
    transform: none;
  }

  .agent-float__base,
  .agent-float__dot,
  .agent-float.is-live .agent-float__host {
    animation: none !important;
  }
}
