/* ============================================================================
   رِماية — مكالمة مع راكان (prototypes/landing/call.html)
   ----------------------------------------------------------------------------
   One screen, one voice. The brief was the calm of Apple's FaceTime audio call
   and ChatGPT's voice mode, in Rimaya's brand: a near-black #07040F room, a slow
   aurora of Deep #331761 and Electric #5C17FD low at the bottom, a faint Violet
   #BB50F8 bloom behind a fluid orb, and a hair of film grain. Deep, Electric and
   Violet are used strictly as LIGHT — the orb, its halo, hairline rims, the
   glass — never as a flat wash over the whole screen.

   Self-contained: it carries its own copy of the brand tokens and the six
   @font-face rules that point at the landing's own `/fonts/…woff2`. Palette per
   AGENTS.md §4, BRAND_IMPLEMENTATION.md and prototypes/admin/BRAND_NOTES.md.

   Motion: the orb is a canvas drawn by js/call.js at 60 fps; every non-essential
   transition is off under `prefers-reduced-motion` (the orb then changes colour
   only). Two call-colour exceptions carry the phone vocabulary the brief asked
   for — a green answer button, a red hang-up button — and they live only in the
   controls. Interface copy stays short; nothing is a sentence in a chip.
   ========================================================================== */

/* ------------------------------------------------------------------ fonts ---- */
@font-face {
  font-family: "Rimaya Arabic";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/fonts/ibm-plex-sans-arabic-arabic-400-normal.woff2") format("woff2");
  unicode-range: U+0600-06FF, U+0750-077F, U+08A0-08FF, U+FB50-FDFF, U+FE70-FEFF;
}
@font-face {
  font-family: "Rimaya Arabic";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/fonts/ibm-plex-sans-arabic-latin-400-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+2000-206F;
}
@font-face {
  font-family: "Rimaya Arabic";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("/fonts/ibm-plex-sans-arabic-arabic-500-normal.woff2") format("woff2");
  unicode-range: U+0600-06FF, U+0750-077F, U+08A0-08FF, U+FB50-FDFF, U+FE70-FEFF;
}
@font-face {
  font-family: "Rimaya Arabic";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("/fonts/ibm-plex-sans-arabic-latin-500-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+2000-206F;
}
@font-face {
  font-family: "Rimaya Arabic";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/fonts/ibm-plex-sans-arabic-arabic-700-normal.woff2") format("woff2");
  unicode-range: U+0600-06FF, U+0750-077F, U+08A0-08FF, U+FB50-FDFF, U+FE70-FEFF;
}
@font-face {
  font-family: "Rimaya Arabic";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/fonts/ibm-plex-sans-arabic-latin-700-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+2000-206F;
}

/* ----------------------------------------------------------------- tokens ---- */
:root {
  --ink: #07040f;

  --deep: #331761;
  --electric: #5c17fd;
  --violet: #bb50f8;

  --text: rgba(255, 255, 255, 0.82);
  --text-2: rgba(255, 255, 255, 0.62);
  --text-3: rgba(255, 255, 255, 0.45);

  --hair: rgba(255, 255, 255, 0.1);
  --hair-2: rgba(255, 255, 255, 0.2);

  --glass: linear-gradient(180deg, rgba(255, 255, 255, 0.085), rgba(255, 255, 255, 0.028));

  /* The two call colours, darkened until white text clears AA (≥4.5:1). */
  --answer: #086b41;
  --answer-2: #0b8552;
  --hangup: #b02a2e;
  --hangup-2: #c93034;
  /* A lighter Violet tint for text: the base #BB50F8 is light and only just
     misses AA as small type. */
  --violet-text: #cf8bff;

  /* WhatsApp. The brand green appears in exactly one place — the hand-off card
     — and the darker ramp is what keeps white text on it at AA. */
  --wa: #25d366;
  --wa-strong: #12924e;
  --wa-deep: #0d7a40;

  --font: "Rimaya Arabic", system-ui, "Segoe UI", Tahoma, sans-serif;

  --r-lg: 20px;
  --r-md: 16px;
  --r-sm: 12px;

  --ease: cubic-bezier(0.22, 1, 0.36, 1);

  /* The orb box (the canvas) is a square that fits the free space in the
     stage, so opening a card shrinks it instead of covering the stack. The
     drawn sphere is 0.8 of the box; the box's other fifth is the room the glow
     and the ripples fade in. Registered so the value can be animated when a
     card opens. */
  --orb: min(68vw, 360px, 68vh);
  --orb-card: min(49vw, 259px, 49vh); /* 0.72 × --orb */
}

@property --orb {
  syntax: "<length>";
  inherits: true;
  initial-value: 300px;
}

/* ------------------------------------------------------------------ reset ---- */
*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  min-height: 100vh;
  min-height: 100dvh;
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.6;
  color: var(--text);
  background-color: var(--ink);
  overflow-x: clip;
}

/* The aurora: two slow bands of Deep and Electric at the foot of the screen and
   a faint Violet bloom up top. It is a fixed layer behind the app, so it never
   scrolls and never sits over a control. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image:
    radial-gradient(115% 62% at 50% 120%, rgba(92, 23, 253, 0.42), transparent 60%),
    radial-gradient(85% 52% at 50% 124%, rgba(51, 23, 97, 0.78), transparent 72%),
    radial-gradient(70% 42% at 50% 4%, rgba(187, 80, 248, 0.1), transparent 72%);
  animation: aurora-drift 26s ease-in-out infinite alternate;
}

@keyframes aurora-drift {
  from {
    transform: translate3d(0, 0, 0) scale(1);
  }
  to {
    transform: translate3d(0, -1.4%, 0) scale(1.05);
  }
}

/* Film grain: static, ~3%, no request, never intercepts pointers. */
.app::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 90;
  pointer-events: none;
  opacity: 0.03;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.8' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 160px 160px;
}

img {
  display: block;
  max-width: 100%;
}

/* `hidden` must win over every class that sets a `display` (the UA rule is
   weaker than any author rule of equal specificity). */
[hidden] {
  display: none !important;
}

h1,
h2,
p {
  margin: 0;
}

button {
  font: inherit;
  color: inherit;
}

a {
  color: inherit;
}

:focus-visible {
  outline: 2px solid var(--violet);
  outline-offset: 3px;
  border-radius: 8px;
}

/* The notice and the two closing screens are where focus goes when they appear
   (docs/ACCESSIBILITY.md, focus policy 1) — focus TARGETS, never controls. They
   carry `tabindex="-1"` and draw no ring of their own, on `:focus` or on
   `:focus-visible` (a browser may call a programmatic focus "visible"): one Tab
   reaches the first control, whose ring is real. */
.notice:focus,
.notice:focus-visible,
.ended:focus,
.ended:focus-visible {
  outline: none;
}

.skip {
  position: absolute;
  inset-block-start: -100px;
  inset-inline-start: 16px;
  z-index: 100;
  padding: 10px 16px;
  border-radius: var(--r-sm);
  background: #fff;
  color: #1a1a1a;
  text-decoration: none;
}
.skip:focus {
  inset-block-start: 12px;
}

/* A visually hidden region that is still announced: the settled caption line
   reaches assistive tech here, once per turn. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* -------------------------------------------------------------------- app ---- */
/* One fixed screen on purpose: the stack has to fit, so the stage shrinks the
   orb instead of pushing the controls out of view. */
.app {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  height: 100vh;
  height: 100dvh;
  min-height: 100vh;
  min-height: 100dvh;
  overflow: hidden;
  padding: calc(env(safe-area-inset-top, 0px) + 12px) clamp(16px, 4vw, 40px)
    calc(env(safe-area-inset-bottom, 0px) + 8px);
}

/* -------------------------------------------------------------------- top ---- */
.top {
  position: relative;
  z-index: 5;
  /* Three cells, one row: the back button at the inline start, the wordmark and
     the page's label together in the centre, the demo chip at the far end. The
     label used to be pushed by whatever space was left, which put it 580px from
     the wordmark on a desktop and on top of it at 360. */
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center;
  gap: 12px;
  min-height: 44px;
  flex: 0 0 auto;
}

.top__brand {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  min-width: 0;
}

.top__back {
  justify-self: start;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-height: 44px;
  padding-block: 10px;
  padding-inline: 8px 12px;
  border-radius: 999px;
  color: var(--text);
  font-size: 14px;
  font-weight: 500;
  text-decoration: none;
  background: rgba(255, 255, 255, 0.045);
  border: 1px solid var(--hair);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  transition: background 220ms var(--ease), border-color 220ms var(--ease);
}
.top__back:hover {
  background: rgba(255, 255, 255, 0.09);
  border-color: var(--hair-2);
}
.top__arrow {
  width: 18px;
  height: 18px;
  color: var(--violet);
}
/* the chevron points to the inline start: right in Arabic, left in English */
[dir="ltr"] .top__arrow {
  transform: rotate(180deg);
}

/* The brand SVG paints a 239×106 wordmark centred on a 264.58 square
   artboard, so a plain `height: 24px` renders a 24px-wide smudge. The span
   crops the artboard to the ink (24px tall, 54.2px wide) and the img is
   scaled to 60px and pulled out of view: logo-horizontal-black.svg inverted
   to white on the dark base. */
.top__logo {
  position: relative;
  flex: 0 0 auto;
  display: block;
  width: 54.2px;
  height: 24px;
  overflow: hidden;
}
.top__logo img {
  position: absolute;
  width: 59.95px;
  height: 59.95px;
  max-width: none;
  inset-block-start: -17.98px;
  inset-inline-start: -2.89px;
  filter: brightness(0) invert(1);
  opacity: 0.92;
}

.top__tag {
  margin-inline-start: 0;
  min-width: 0;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.01em;
  color: rgba(255, 255, 255, 0.86);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The one-line AI notice: plain text at the top, never a chip. The sentence is
   its own row and the two actions are their own row — at 360 they used to wrap
   into a third cramped line and read as one long sentence. */
.privacy {
  position: relative;
  z-index: 4;
  flex: 0 0 auto;
  padding-inline: 20px;
  text-align: center;
  font-size: 12px;
  line-height: 1.5;
  color: var(--text-2);
  display: grid;
  justify-items: center;
  gap: 3px;
}
.privacy__line {
  margin: 0;
  max-width: 42ch;
  text-wrap: balance;
}
.privacy__acts {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  column-gap: 20px;
}
.privacy a {
  color: var(--text);
  text-decoration: underline;
  text-underline-offset: 2px;
  white-space: nowrap;
}
.privacy a:hover {
  color: #fff;
}

/* «لا تحفظ زيارتي»: a quiet one-line action under the notice, never a button
   competing with the call. Its hit area is 44px tall without pushing the stage
   down — the line itself is one small link. */
.privacy__forget {
  position: relative;
  margin-block-start: 0;
  padding: 0 4px;
  border: 0;
  background: none;
  color: var(--text-2);
  font: inherit;
  font-size: 11.5px;
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}
.privacy__forget::after {
  content: "";
  position: absolute;
  inset: -15px -10px;
}
.privacy__forget:hover {
  color: var(--text);
}
.privacy__forget:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 3px;
  border-radius: 4px;
}
.privacy__forget[disabled] {
  color: var(--text-3);
  text-decoration: none;
  cursor: default;
}

/* Demo-only: a quiet chip in the top bar, never over the stage. */
.top__demo {
  justify-self: end;
  flex: 0 0 auto;
  padding: 3px 9px;
  border-radius: 999px;
  border: 1px solid var(--hair);
  background: rgba(255, 255, 255, 0.055);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.03em;
  color: var(--text-2);
  white-space: nowrap;
}

/* ------------------------------------------------------------------ stage ---- */
.stage {
  position: relative;
  z-index: 2;
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  padding-block: 6px;
  text-align: center;
}

/* The orb box takes whatever the stack leaves, so opening a card scales the
   orb down instead of letting the card cover the name, the status and the
   captions. Nothing here may be shrunk except the orb. */
.orbwrap {
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
  display: grid;
  place-items: center;
  /* a size container: `cqmin` below is the smaller of the two free axes */
  container-type: size;
}

.orbfit {
  position: relative;
  /* container units: the same figure on both axes, so the orb box is always
     a square, never an ellipse squeezed by a short screen */
  width: min(var(--orb), 100cqmin);
  height: min(var(--orb), 100cqmin);
  /* the clamp is what the transition cannot outrun: while the box eases down
     it may never be bigger than the room it has, so it can never touch the
     name, the status or the captions */
  max-width: 100cqmin;
  max-height: 100cqmin;
  /* the card's arrival, the captions' switch and the orb's ease-down share one
     curve, so the orb only ever gets smaller, never bounces */
  transition: --orb 380ms var(--ease);
}
#app[data-card="1"] .orbfit {
  --orb: var(--orb-card);
}

/* A faint Violet bloom behind the sphere — the canvas draws the halo proper. */
.orb-glow {
  position: absolute;
  inset: 12%;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 55%, rgba(187, 80, 248, 0.24), transparent 68%);
  filter: blur(10px);
  pointer-events: none;
}

/* The canvas is the orb box: the sphere is 0.8 of it and the glow and the
   ripples fade out inside it, so the orb never paints over its neighbours. */
.orb {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: block;
  width: 100%;
  height: 100%;
}

.who,
.status,
.caption,
.cardslot {
  flex: 0 0 auto;
}

.who {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.who__name {
  font-size: clamp(30px, 7.4vw, 38px);
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: -0.01em;
  color: #fff;
}
.who__role {
  font-size: 14px;
  font-weight: 500;
  color: var(--text-2);
}

/* ----------------------------------------------------------------- status ---- */
/* A small pill: a live dot and «متصل · 00:42». It reserves its own line so the
   orb never moves when the clock appears. */
.status {
  margin-block-start: 12px;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 5px 14px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.045);
  border: 1px solid var(--hair);
  font-size: 14px;
  font-weight: 500;
  color: var(--text);
  font-variant-numeric: tabular-nums;
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
}
.status[data-on="0"] {
  display: none;
}
.status__dot {
  width: 7px;
  height: 7px;
  flex: 0 0 auto;
  border-radius: 50%;
  background: var(--violet-text);
  box-shadow: 0 0 0 4px rgba(187, 80, 248, 0.14);
}
.status[data-mood="connecting"] .status__dot {
  animation: dot-pulse 1.2s ease-in-out infinite;
}
.status[data-mood="listening"] .status__dot {
  background: #7fe3b0;
  box-shadow: 0 0 0 4px rgba(127, 227, 176, 0.14);
}
.status[data-mood="speaking"] .status__dot {
  background: var(--violet);
  box-shadow: 0 0 0 4px rgba(187, 80, 248, 0.22);
}
@keyframes dot-pulse {
  0%,
  100% {
    opacity: 0.4;
    transform: scale(0.85);
  }
  50% {
    opacity: 1;
    transform: scale(1);
  }
}
.status__clock {
  color: var(--text-2);
}
.status__clock:not(:empty)::before {
  content: "·";
  margin-inline: 7px;
}
/* The last minute, the same minute the model is told to close in: the pill
   warms gently — a tint and a border, no flashing. */
.status[data-soon="1"] {
  background: rgba(240, 184, 102, 0.1);
  border-color: rgba(240, 184, 102, 0.34);
  color: #ffe3ba;
}
.status[data-soon="1"] .status__clock {
  color: #f2c98a;
}
.status[data-soon="1"] .status__dot {
  background: #f0b866;
  box-shadow: 0 0 0 4px rgba(240, 184, 102, 0.16);
}

/* --------------------------------------------------------------- captions ---- */
/* The caption stage: Rakan's current line is the karaoke line (words arrive at
   35% white and go full white as they are spoken); the previous line lifts away
   above; the visitor's words sit below under a small «أنت» label. The agent box
   keeps a fixed two-line height, so a caption never nudges the orb. */
.caption {
  width: min(100%, 40rem);
  max-width: 92vw;
  margin-block-start: 10px;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 8px;
}
.cap-agent {
  display: grid;
  grid-template-rows: 1.6em minmax(0, auto);
  align-content: start;
  min-height: calc(2 * 1.6em);
  font-size: 20px;
  line-height: 1.6;
}
.cap-line {
  margin: 0;
  font-size: inherit;
  line-height: inherit;
  text-wrap: balance;
}

/* The karaoke line. `cap-w` spans are the words; a soft fade-in per word. The
   line keeps the latest sentence whole: it grows to four lines and then scrolls,
   so an answer is never cut with «…». */
.cap-line--now {
  grid-row: 2;
  color: rgba(255, 255, 255, 0.9);
  display: block;
  max-height: 6.4em;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: rgba(255, 255, 255, 0.22) transparent;
}
.cap-line--now.is-plain {
  display: block;
}
.cap-line--now .cap-w {
  opacity: 0.35;
  transition: opacity 280ms var(--ease);
}
.cap-line--now .cap-w.is-said {
  opacity: 1;
}

/* The line that is leaving owns its own grid row and only fades and lifts, so
   it can never paint over the line that replaced it. */
.cap-line--old {
  grid-row: 1;
  color: rgba(255, 255, 255, 0.9);
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 1;
  overflow: hidden;
  opacity: 0.55;
  transform: translateY(0);
  transition: opacity 600ms var(--ease), transform 600ms var(--ease);
}
.cap-line--old.is-out {
  opacity: 0;
  transform: translateY(-10px);
}

.cap-visitor {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 8px;
  font-size: 14.5px;
  line-height: 1.5;
  color: var(--text-2);
  transition: opacity 420ms var(--ease);
}
.cap-visitor.is-out {
  opacity: 0;
}
.cap-visitor__label {
  flex: 0 0 auto;
  padding: 1px 9px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.07);
  border: 1px solid var(--hair);
  font-size: 11px;
  font-weight: 500;
  color: var(--text-2);
}
.cap-visitor__text {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
  text-align: start;
}

/* ------------------------------------------------------------------- card ---- */
/* The card is part of the stack, not an overlay: it sits above the controls
   and the stack above it moves up to make room. The slot animates its own
   height, so the orb and the text travel together instead of jumping. */
.cardslot {
  display: grid;
  grid-template-rows: 1fr;
  flex: 0 0 auto;
  width: 100%;
  margin-block-start: 12px;
  animation: slot-in 380ms var(--ease) both;
}
@keyframes slot-in {
  from {
    grid-template-rows: 0fr;
  }
  to {
    grid-template-rows: 1fr;
  }
}

.card {
  position: relative;
  z-index: 40;
  min-height: 0;
  overflow: hidden;
  width: min(100%, 23rem);
  margin-inline: auto;
  padding: 16px 16px 14px;
  border-radius: var(--r-lg);
  background: var(--glass);
  border: 1px solid rgba(255, 255, 255, 0.1);
  box-shadow: 0 40px 90px -50px rgba(92, 23, 253, 0.8), 0 2px 12px -8px rgba(0, 0, 0, 0.7);
  -webkit-backdrop-filter: blur(20px) saturate(140%);
  backdrop-filter: blur(20px) saturate(140%);
  text-align: start;
  animation: card-in 320ms var(--ease) both;
}
@keyframes card-in {
  from {
    opacity: 0;
    transform: translateY(12px) scale(0.985);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

.card__close {
  position: absolute;
  inset-block-start: 10px;
  inset-inline-end: 10px;
  width: 44px;
  height: 44px;
  margin: -5px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 1px solid transparent;
  border-radius: 50%;
  background: transparent;
  color: var(--text-2);
  cursor: pointer;
  transition: background 200ms var(--ease), color 200ms var(--ease);
}
.card__close:hover {
  background: rgba(255, 255, 255, 0.1);
  color: #fff;
}
.card__close svg {
  width: 17px;
  height: 17px;
}

.card__title {
  font-size: 16px;
  font-weight: 700;
  color: #fff;
  padding-inline-end: 36px;
}

.card__body {
  margin-block-start: 6px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 13px;
  color: var(--text);
}
.card__row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding-block: 3px;
  border-block-end: 1px solid rgba(255, 255, 255, 0.06);
}
.card__row:last-child {
  border-block-end: 0;
}
.card__row b {
  font-weight: 700;
  color: #fff;
}
.card[data-kind="plans"] .card__row b {
  font-size: 15px;
}
.card__price {
  font-variant-numeric: tabular-nums;
  color: var(--violet-text);
  font-weight: 700;
  white-space: nowrap;
}
.card[data-kind="plans"] .card__price {
  font-size: 14px;
}

.card__action {
  margin-block-start: 10px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: 42px;
  padding: 10px 16px;
  border-radius: 999px;
  border: 1px solid var(--hair-2);
  background: rgba(255, 255, 255, 0.06);
  color: #fff;
  font-weight: 500;
  font-size: 14px;
  text-decoration: none;
  transition: background 220ms var(--ease), transform 220ms var(--ease);
}
.card__action:hover {
  background: rgba(255, 255, 255, 0.12);
}

/* The hand-off card: «أحمد»'s WhatsApp. The one place the brand green appears.
   The number is drawn LTR inside the RTL card, where a phone number belongs. */
.card__row--wa {
  align-items: center;
}
.card__num {
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
  color: var(--wa);
  white-space: nowrap;
}
.card[data-kind="whatsapp"] .card__action.is-wa {
  border-color: transparent;
  background: linear-gradient(180deg, var(--wa-strong), var(--wa-deep));
  font-weight: 700;
  box-shadow: 0 18px 40px -20px rgba(18, 146, 78, 0.85);
}
.card[data-kind="whatsapp"] .card__action.is-wa:hover {
  background: linear-gradient(180deg, #16a659, #0e8a48);
}

/* ----------------------------------------------------------------- notice ---- */
.notice {
  width: min(100%, 34rem);
  padding: 26px 24px;
  border-radius: var(--r-lg);
  background: var(--glass);
  border: 1px solid var(--hair);
  -webkit-backdrop-filter: blur(16px);
  backdrop-filter: blur(16px);
}
.notice__title {
  font-size: clamp(20px, 5.4vw, 26px);
  font-weight: 700;
  color: #fff;
}
.notice__text {
  margin-block-start: 8px;
  font-size: 14.5px;
  color: var(--text);
}
.notice__acts {
  margin-block-start: 18px;
  display: grid;
  grid-template-columns: 1fr;
  gap: 8px;
}
.notice__acts .btn {
  width: 100%;
  justify-content: center;
}

/* hide the middle of the stage when the call cannot run */
#app[data-state="unavailable"] .orbwrap,
#app[data-state="unavailable"] .who,
#app[data-state="unavailable"] .status,
#app[data-state="unavailable"] .caption {
  display: none;
}
#app[data-state="unavailable"] .stage {
  justify-content: center;
}

/* ------------------------------------------------------------------ chat ---- */
/* The typed surface: a plain transcript on the same near-black stage. It takes
   the orb's room while it is open so long answers never fight the art. */
.chatlog {
  width: min(100%, 40rem);
  max-width: 92vw;
  flex: 1 1 auto;
  min-height: 0;
  max-height: min(58vh, 30rem);
  margin-block: 8px;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: rgba(255, 255, 255, 0.22) transparent;
  outline: none;
}
.chatlog:focus,
.chatlog:focus-visible {
  outline: none;
}
.chatlog__list {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 2px;
}
.chat__turn {
  max-width: 88%;
  padding: 10px 14px;
  border-radius: 16px;
  font-size: 15px;
  line-height: 1.65;
  text-align: start;
}
.chat__turn--assistant {
  align-self: flex-start;
  background: rgba(255, 255, 255, 0.075);
  border: 1px solid var(--hair);
  color: #fff;
}
.chat__turn--user {
  align-self: flex-end;
  background: linear-gradient(180deg, rgba(116, 57, 255, 0.5), rgba(92, 23, 253, 0.36));
  border: 1px solid rgba(187, 80, 248, 0.34);
  color: #fff;
}
.chat__turn--system {
  align-self: center;
  max-width: 100%;
  padding: 6px 10px;
  background: transparent;
  color: var(--text-2);
  font-size: 13px;
  text-align: center;
}
.chat__text {
  margin: 0;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
/* A turn that could not be answered is a small card, not a grey line: the reason
   and the same two ways forward the unavailable card offers. */
.chat__turn--card {
  align-self: stretch;
  max-width: 100%;
  padding: 12px 14px;
  border: 1px solid var(--hair-2);
  border-radius: 16px;
  background: rgba(255, 255, 255, 0.055);
  color: var(--text);
  font-size: 14px;
  text-align: start;
}
.chat__acts {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-block-start: 10px;
}
.chat__act {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 8px 16px;
  border-radius: 999px;
  border: 1px solid var(--hair-2);
  color: var(--text);
  font-size: 13.5px;
  font-weight: 600;
  text-decoration: none;
}
.chat__act:hover {
  border-color: #fff;
}
.chat__act--wa {
  border-color: transparent;
  background: linear-gradient(180deg, var(--wa-strong), var(--wa-deep));
  color: #fff;
}
.chat__wa {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  margin-block-start: 8px;
  padding: 8px 18px;
  border-radius: 999px;
  background: linear-gradient(180deg, var(--wa-strong), var(--wa-deep));
  color: #fff;
  font-weight: 700;
  font-size: 14px;
  text-decoration: none;
}
.chatlog__typing {
  padding: 4px 6px 0;
  font-size: 12.5px;
  color: var(--text-2);
}

/* The typed mode owns the stage: no orb, no captions, no clock. */
#app[data-chat="1"] .orbwrap,
#app[data-chat="1"] .who,
#app[data-chat="1"] .status,
#app[data-chat="1"] .caption {
  display: none;
}
#app[data-chat="1"] .stage {
  justify-content: flex-start;
  padding-block-start: 8px;
}

.composer {
  width: min(100%, 34rem);
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 5px 5px 5px 6px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.075);
  border: 1px solid var(--hair-2);
}
.composer__input {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 40px;
  padding: 8px 12px;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: #fff;
  font: inherit;
  font-size: 15px;
}
.composer__input::placeholder {
  color: var(--text-3);
}
.composer__input:focus {
  outline: none;
}
.composer__input:focus-visible {
  outline: 2px solid rgba(187, 80, 248, 0.6);
  outline-offset: 1px;
}
.composer__send {
  flex: 0 0 auto;
  min-height: 44px;
  padding: 0 18px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(180deg, #7439ff, var(--electric));
  color: #fff;
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
}
.composer__send:disabled {
  opacity: 0.45;
  cursor: default;
}
.chat-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 6px 12px;
  border: 0;
  background: transparent;
  color: var(--text-2);
  font: inherit;
  font-size: 13px;
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}
.chat-toggle:hover {
  color: #fff;
}
#app[data-state="live"] .chat-toggle,
#app[data-state="connecting"] .chat-toggle,
#app[data-state="ended"] .chat-toggle,
#app[data-state="exhausted"] .chat-toggle,
#app[data-state="live"] .composer,
#app[data-state="connecting"] .composer,
#app[data-state="ended"] .composer,
#app[data-state="exhausted"] .composer {
  display: none;
}

/* ------------------------------------------------------------ end screens ---- */
/* «انتهت المكالمة» and the exhausted screen own the whole screen: everything the
   call drew — the orb, the name, the pill, the captions and the
   dock — fades out under the panel in 250 ms and is then out of rendering, so
   nothing glows through the title or the WhatsApp button and no stray label sits
   under where the dock was. Only the panel and the top bar stay (the top bar is
   how the visitor leaves). The transition is declared *here*, in the hidden
   state, so leaving the state brings everything back at once. */
#app[data-state="ended"] .orbwrap,
#app[data-state="ended"] .who,
#app[data-state="ended"] .status,
#app[data-state="ended"] .caption,
#app[data-state="ended"] .cardslot,
#app[data-state="ended"] .dock,
#app[data-state="exhausted"] .orbwrap,
#app[data-state="exhausted"] .who,
#app[data-state="exhausted"] .status,
#app[data-state="exhausted"] .caption,
#app[data-state="exhausted"] .cardslot,
#app[data-state="exhausted"] .dock {
  opacity: 0;
  visibility: hidden;
  transition: opacity 250ms var(--ease), visibility 0s linear 250ms;
}

/* --------------------------------------------------------------- controls ---- */
.dock {
  position: relative;
  z-index: 30;
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  padding-block: 10px calc(6px + env(safe-area-inset-bottom, 0px));
}
/* The notice screens (unavailable, busy, mic, error) hide the dock outright;
   the two end screens fade it out with the rest of the stack. A revealed
   composer is the exception: the typed fallback must be reachable exactly when
   the call is not. */
#app[data-state="unavailable"] .dock {
  display: none;
}
#app[data-state="unavailable"][data-composer="1"] .dock {
  display: flex;
}
#app[data-state="unavailable"] .controls {
  display: none;
}
#app[data-state="unavailable"][data-composer="1"] .dock__hint {
  display: none;
}

.dock__hint {
  min-height: 1.4em;
  font-size: 13.5px;
  color: var(--text-2);
  text-align: center;
}
.dock__hint:empty {
  min-height: 0;
}
.dock__hint.is-soon {
  color: var(--violet-text);
  font-weight: 500;
}

.sound-btn {
  padding: 9px 18px;
  border-radius: 999px;
  border: 1px solid rgba(187, 80, 248, 0.5);
  background: rgba(187, 80, 248, 0.16);
  color: #fff;
  font-size: 13.5px;
  font-weight: 500;
  cursor: pointer;
  transition: background 200ms var(--ease);
}
.sound-btn:hover {
  background: rgba(187, 80, 248, 0.28);
}

/* A floating glass dock, safe-area aware. */
.controls {
  display: flex;
  align-items: flex-start;
  justify-content: center;
  gap: clamp(16px, 5.4vw, 34px);
  padding: 10px clamp(16px, 5vw, 24px);
  border-radius: 30px;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.085), rgba(255, 255, 255, 0.03));
  border: 1px solid var(--hair);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
  backdrop-filter: blur(18px) saturate(140%);
  box-shadow: 0 30px 70px -46px rgba(0, 0, 0, 0.95);
}

.ctrl {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
}
.ctrl:disabled {
  cursor: not-allowed;
}

.ctrl__ico {
  display: grid;
  place-items: center;
  width: 52px;
  height: 52px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.07);
  border: 1px solid var(--hair);
  color: #fff;
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  transition: background 200ms var(--ease), border-color 200ms var(--ease), transform 160ms var(--ease);
}
.ctrl__ico svg {
  width: 22px;
  height: 22px;
}
.ctrl:hover:not(:disabled) .ctrl__ico {
  background: rgba(255, 255, 255, 0.14);
  border-color: var(--hair-2);
}
.ctrl:active:not(:disabled) .ctrl__ico {
  transform: scale(0.94);
}
.ctrl:disabled .ctrl__ico {
  opacity: 0.4;
}
.ctrl__lbl {
  font-size: 11.5px;
  font-weight: 500;
  color: var(--text-2);
  white-space: nowrap;
}
.ctrl:disabled .ctrl__lbl {
  color: var(--text-3);
}

/* muted state: the mic slash shows, the tile goes quiet */
.ctrl--mute[aria-pressed="true"] .ctrl__ico {
  background: rgba(229, 72, 77, 0.18);
  border-color: rgba(229, 72, 77, 0.5);
  color: #ffd9da;
}
.ctrl--mute .ico-mic__slash {
  opacity: 0;
}
.ctrl--mute[aria-pressed="true"] .ico-mic__slash {
  opacity: 1;
}

/* captions off: dim the tile */
.ctrl--cap[aria-pressed="false"] .ctrl__ico {
  opacity: 0.55;
}

/* the answer button: large, green, unmistakably "start", breathing softly */
.ctrl--start .ctrl__ico {
  width: auto;
  height: 64px;
  min-width: 64px;
  padding-inline: 26px;
  border-radius: 999px;
  background: linear-gradient(180deg, var(--answer-2), var(--answer));
  border: 1px solid rgba(255, 255, 255, 0.22);
  box-shadow: 0 18px 40px -18px rgba(11, 133, 82, 0.7);
}
#app[data-state="idle"] .ctrl--start .ctrl__ico {
  animation: start-pulse 2.8s ease-in-out infinite;
}
@keyframes start-pulse {
  0%,
  100% {
    box-shadow: 0 0 0 0 rgba(11, 133, 82, 0.34), 0 18px 40px -18px rgba(11, 133, 82, 0.7);
  }
  50% {
    box-shadow: 0 0 0 13px rgba(11, 133, 82, 0), 0 18px 40px -18px rgba(11, 133, 82, 0.7);
  }
}
.ctrl--start:hover:not(:disabled) .ctrl__ico {
  background: linear-gradient(180deg, #0a7a4c, #076039);
}
.ctrl--start .ctrl__lbl {
  font-size: 14px;
  font-weight: 700;
  color: #fff;
}

/* the hang-up button: the one red circle */
.ctrl--end .ctrl__ico {
  width: 64px;
  height: 64px;
  background: linear-gradient(180deg, var(--hangup-2), var(--hangup));
  border-color: rgba(255, 255, 255, 0.22);
  box-shadow: 0 18px 40px -18px rgba(176, 42, 46, 0.75);
}
.ctrl--end .ctrl__ico svg {
  width: 26px;
  height: 26px;
  transform: rotate(133deg);
}
.ctrl--end:hover:not(:disabled) .ctrl__ico {
  background: linear-gradient(180deg, #d63b40, #a5262a);
}
.ctrl--end .ctrl__lbl {
  font-weight: 700;
  color: #fff;
}

/* ------------------------------------------------------------------ ended ---- */
.ended {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: grid;
  place-items: center;
  padding: 24px;
  background: rgba(5, 3, 10, 0.72);
  -webkit-backdrop-filter: blur(16px);
  backdrop-filter: blur(16px);
  animation: fade-in 320ms var(--ease) both;
}
@keyframes fade-in {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}
.ended__in {
  width: min(100%, 24rem);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  text-align: center;
}
.ended__mark {
  display: grid;
  place-items: center;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  color: var(--violet);
  background: rgba(187, 80, 248, 0.12);
  border: 1px solid rgba(187, 80, 248, 0.35);
  margin-block-end: 4px;
}
.ended__mark svg {
  width: 26px;
  height: 26px;
}
.ended__title {
  font-size: clamp(22px, 6vw, 28px);
  font-weight: 700;
  color: #fff;
}
.ended__sub {
  font-size: 14px;
  color: var(--text-2);
  min-height: 1.4em;
}
.ended__acts {
  margin-block-start: 10px;
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.ended__back {
  margin-block-start: 6px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 10px 16px;
  font-size: 13.5px;
  color: var(--text-2);
  text-decoration: none;
  border-block-end: 1px solid transparent;
}
.ended__back:hover {
  color: #fff;
  border-block-end-color: var(--hair-2);
}

/* -------------------------------------------------------------------- btn ---- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 12px 20px;
  border-radius: 999px;
  border: 1px solid transparent;
  font-size: 15px;
  font-weight: 500;
  text-decoration: none;
  cursor: pointer;
  transition: background 220ms var(--ease), transform 160ms var(--ease);
}
.btn:active {
  transform: scale(0.98);
}
.btn--primary {
  background: linear-gradient(180deg, #7439ff, var(--electric));
  color: #fff;
  box-shadow: 0 18px 44px -20px rgba(92, 23, 253, 0.8);
}
.btn--primary:hover {
  background: linear-gradient(180deg, #8652ff, #4a0fe0);
}
.btn--ghost {
  background: rgba(255, 255, 255, 0.06);
  border-color: var(--hair-2);
  color: #fff;
}
.btn--ghost:hover {
  background: rgba(255, 255, 255, 0.12);
}

/* The hand-off, wherever it appears: the WhatsApp card's action and the two end
   screens. The green ramp is the same one the card uses. */
.btn--wa {
  background: linear-gradient(180deg, var(--wa-strong), var(--wa-deep));
  color: #fff;
  font-weight: 700;
  box-shadow: 0 18px 44px -22px rgba(18, 146, 78, 0.9);
}
.btn--wa:hover {
  background: linear-gradient(180deg, #16a659, #0e8a48);
}
.ended__mark--wa {
  color: var(--wa);
  background: rgba(37, 211, 102, 0.12);
  border-color: rgba(37, 211, 102, 0.34);
}

/* ------------------------------------------------------------- demo badge ---- */
/* The demo chip lives in the top bar (see `.top__demo`); nothing sits at the
   foot of the stage any more, so a caption can never meet a label. */

/* ------------------------------------------------- wider screens (≥768) ---- */
@media (min-width: 768px) {
  :root {
    --orb: min(46vw, 360px, 68vh);
    --orb-card: min(33vw, 259px, 49vh);
  }
}

/* ------------------------------------------------- the three plans inline ---- */
/* Whenever height is scarce (a low desktop window, a phone in landscape, a
   small phone) the plans share one row: the card stays short so the orb keeps a
   visible circle above it. */
@media (min-width: 900px) and (max-height: 860px), (max-height: 700px) {
  .card[data-kind="plans"] .card__body {
    flex-direction: row;
    gap: 8px;
  }
  .card[data-kind="plans"] .card__row {
    flex: 1 1 0;
    flex-direction: column;
    align-items: flex-start;
    justify-content: flex-start;
    gap: 2px;
    min-width: 0;
    padding-block: 2px;
    border-block-end: 0;
  }
  .card[data-kind="plans"] .card__price {
    font-size: 14px;
  }
}

/* Wide but low: the card can also be a little wider. */
@media (min-width: 900px) and (max-height: 860px) {
  .card {
    width: min(100%, 26rem);
  }
}

/* A narrow phone: the three columns need a smaller price label to hold
   "199 SAR / month" inside one third of the card. */
@media (max-width: 480px) {
  .card[data-kind="plans"] .card__body {
    gap: 6px;
  }
  .card[data-kind="plans"] .card__price {
    font-size: 14px;
  }
}

/* Phones: the caption stage steps down a size, the dock tightens. */
@media (max-width: 600px) {
  .cap-agent {
    font-size: 18px;
  }
  .caption {
    margin-block-start: 8px;
  }
}

/* Very short screens: the card and the dock give up a little room. */
@media (max-height: 700px) {
  .cap-agent {
    min-height: calc(2 * 1.5em);
    font-size: 17px;
  }
  .card {
    padding: 13px 14px 12px;
  }
  .card__body {
    font-size: 12.5px;
  }
  .card__action {
    margin-block-start: 8px;
    min-height: 38px;
  }
  .dock {
    gap: 8px;
    padding-block: 6px calc(4px + env(safe-area-inset-bottom, 0px));
  }
  .dock__hint {
    font-size: 12.5px;
  }
  .ctrl__ico {
    width: 46px;
    height: 46px;
  }
  .ctrl--start .ctrl__ico,
  .ctrl--end .ctrl__ico {
    height: 56px;
  }
  .ctrl--end .ctrl__ico {
    width: 56px;
  }
}

/* --------------------------------------------------- reduced motion mode ---- */
/* The spec's hard rule: a static orb that only shifts colour, no aurora drift,
   no pulse, no fade. The canvas itself drops to colour-only redraws. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}
