/* Public-chat — port of the React SPA's look.
 *
 * Layered so the visual order matches the original:
 *   1. Black backdrop
 *   2. Spotlight blob + cursor halo (decorative)
 *   3. Hero grid (title + 3D scene)
 *   4. Chat overlay (centered, full bleed)
 *   5. Mobile-only header (top), composer slides up from bottom on mobile
 *
 * Mobile vs desktop is purely media-query based — same DOM, different
 * presentation. State (loading / error / chat) is toggled by a class on
 * `<main id="chat-root">`.
 */

* { box-sizing: border-box; }

html, body { height: 100%; margin: 0; padding: 0; background: #000; color: #fff; }

body {
  font-family: "Vazirmatn", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI",
    Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow: hidden;
}

/* ─── Top-level layering ─────────────────────────────────────────────
 * The chat screen — including the spline canvas — is *always* mounted
 * so the WebGL canvas measures real dimensions on its first paint.
 * Loading and error become full-bleed overlays with a higher z-index;
 * they cover the chat visually but the scene below keeps rendering at
 * its real size, which means the robot is already there when the
 * overlay clears (no resize-to-zero quirk that the React app worked
 * around by calling app.setSize after onLoad).
 */
#chat-root { position: relative; width: 100vw; height: 100vh; min-height: 100svh; overflow: hidden; }
/* The chat section must take the full viewport so its descendants
 * (hero-grid → hero-scene → spline-viewer canvas) can resolve
 * `height: 100%` to a real pixel value. Without this the WebGL
 * canvas measures 0px tall and renders nothing. */
.screen-chat { display: block; width: 100%; height: 100%; position: relative; }

.screen-loading,
.screen-error {
  position: absolute; inset: 0;
  z-index: 50;
  display: none;
  align-items: center; justify-content: center;
  background: #000;
}
.state-loading .screen-loading { display: flex; }
.state-error   .screen-error   { display: flex; }
.loading-card {
  display: flex; flex-direction: column; align-items: center; gap: 1rem;
  color: rgba(255,255,255,0.55);
}
.spinner {
  width: 2rem; height: 2rem;
  border: 2px solid rgba(255,255,255,0.2);
  border-top-color: #fff;
  border-radius: 50%;
  animation: spin 1s linear infinite;
}
.error-card { text-align: center; max-width: 28rem; padding: 0 1rem; color: rgba(255,255,255,0.8); }
.error-card h1 { font-size: 1.25rem; font-weight: 600; color: #fff; margin: 0 0 0.5rem; }
.error-card p  { margin: 0; color: rgba(255,255,255,0.55); line-height: 1.6; }

/* ─── Floating action menu (bottom-left) ──────────────────────────────
 * Hover-expanding stack of pills, sized + coloured to match the chat
 * surface (dark frosted glass, no brand accent, no glow). Trigger
 * sits at the bottom; on hover (or tap, via chat.js `data-open`) the
 * items spring upward with a small cascade.
 */
.fab {
  --fab-surface:        rgba(20,20,22,0.55);
  --fab-surface-strong: rgba(20,20,22,0.85);
  --fab-border:         rgba(255,255,255,0.12);
  --fab-border-strong:  rgba(255,255,255,0.22);
  --fab-text:           rgba(255,255,255,0.94);
  position: absolute;
  bottom: calc(env(safe-area-inset-bottom) + 1.25rem);
  left: 1.25rem;
  z-index: 40;
  /* `column` puts the trigger (last source child) at the bottom and
   * the menu (first child) above it — so the stack expands UPWARD. */
  display: flex; flex-direction: column; align-items: flex-start;
  gap: 0.625rem;
}

/* Trigger: dark frosted disc with + that rotates to × on open.
 * Matches the chat composer's frosted look — no brand glow. */
.fab-trigger {
  width: 52px; height: 52px;
  border-radius: 9999px;
  border: 1px solid var(--fab-border);
  background: var(--fab-surface);
  -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
  color: var(--fab-text);
  display: inline-flex; align-items: center; justify-content: center;
  cursor: pointer;
  transition:
    background 180ms ease,
    border-color 180ms ease,
    transform 180ms cubic-bezier(0.2, 0.7, 0.2, 1);
}
.fab-trigger:hover {
  background: var(--fab-surface-strong);
  border-color: var(--fab-border-strong);
  transform: translateY(-1px);
}
.fab-trigger:active { transform: translateY(0); }
.fab-trigger-icon {
  width: 22px; height: 22px;
  transition: transform 220ms cubic-bezier(0.2, 0.7, 0.2, 1);
}
.fab:hover .fab-trigger-icon,
.fab[data-open="true"] .fab-trigger-icon { transform: rotate(45deg); }

/* Menu list — `column-reverse` so the primary action (Sign up, first
 * in source for screen readers) sits closest to the trigger visually. */
.fab-menu {
  list-style: none; padding: 0; margin: 0;
  display: flex; flex-direction: column-reverse;
  gap: 0.5rem;
  pointer-events: none;
}
.fab-menu > li {
  opacity: 0;
  transform: translateY(8px) scale(0.92);
  transform-origin: 0 100%;
  transition:
    opacity 180ms ease,
    transform 220ms cubic-bezier(0.2, 0.7, 0.2, 1);
  transition-delay: 0ms;
}
.fab:hover .fab-menu,
.fab[data-open="true"] .fab-menu { pointer-events: auto; }
.fab:hover .fab-menu > li,
.fab[data-open="true"] .fab-menu > li {
  opacity: 1;
  transform: translateY(0) scale(1);
}
/* Cascade: the item nearest the trigger appears first. With
 * `column-reverse` the visually-bottom item is `:nth-child(1)`. */
.fab:hover .fab-menu > li:nth-child(1),
.fab[data-open="true"] .fab-menu > li:nth-child(1) { transition-delay: 30ms; }
.fab:hover .fab-menu > li:nth-child(2),
.fab[data-open="true"] .fab-menu > li:nth-child(2) { transition-delay: 80ms; }
.fab:hover .fab-menu > li:nth-child(3),
.fab[data-open="true"] .fab-menu > li:nth-child(3) { transition-delay: 130ms; }

/* Pill — same surface as the trigger; subtle slide-in on hover. */
.fab-item {
  display: inline-flex; align-items: center; gap: 0.5rem;
  height: 38px; padding: 0 0.95rem 0 0.7rem;
  border-radius: 9999px;
  border: 1px solid var(--fab-border);
  background: var(--fab-surface);
  -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
  color: var(--fab-text); text-decoration: none;
  font: 500 0.8125rem/1 inherit; cursor: pointer; white-space: nowrap;
  font-family: inherit;
  transition:
    background 150ms ease,
    border-color 150ms ease,
    transform 150ms ease;
}
.fab-item:hover {
  background: var(--fab-surface-strong);
  border-color: var(--fab-border-strong);
  transform: translateX(2px);
}
.fab-item:active { transform: translateX(0); }
.fab-item svg { width: 16px; height: 16px; opacity: 0.9; }

/* Primary action gets a slightly brighter border — same surface, no
 * accent fill, no glow. */
.fab-item-primary {
  border-color: var(--fab-border-strong);
}
.fab-item-primary:hover {
  background: var(--fab-surface-strong);
  border-color: rgba(255,255,255,0.32);
}

/* Language sub-popup — opens to the right of the Language pill. */
.fab-item-lang { position: relative; }
.fab-lang-popup {
  position: absolute;
  bottom: 50%;
  left: calc(100% + 0.5rem);
  transform: translateY(50%) translateX(-4px);
  opacity: 0;
  pointer-events: none;
  display: flex; flex-direction: column; gap: 2px;
  min-width: 9rem;
  padding: 6px;
  border-radius: 14px;
  border: 1px solid var(--fab-border-strong);
  background: var(--fab-surface-strong);
  -webkit-backdrop-filter: blur(20px); backdrop-filter: blur(20px);
  box-shadow: 0 12px 36px rgba(0, 0, 0, 0.55);
  transition:
    opacity 160ms ease,
    transform 200ms cubic-bezier(0.2, 0.7, 0.2, 1);
}
.fab-item-lang[data-open="true"] .fab-lang-popup {
  opacity: 1;
  pointer-events: auto;
  transform: translateY(50%) translateX(0);
}
.fab-lang-form { margin: 0; padding: 0; }
.fab-lang-option {
  width: 100%; text-align: start;
  display: block;
  padding: 8px 12px;
  border-radius: 10px;
  border: 0;
  background: transparent;
  color: var(--fab-text);
  font: 500 0.8125rem/1.2 inherit;
  font-family: inherit;
  cursor: pointer;
  transition: background 120ms ease, color 120ms ease;
}
.fab-lang-option:hover { background: rgba(255,255,255,0.07); }
.fab-lang-option.is-current { color: var(--fab-accent); }

/* Mobile: still bottom-left, but tuck under the composer's safe area
 * so it doesn't fight the keyboard. */
@media (max-width: 767px) {
  .fab {
    bottom: calc(env(safe-area-inset-bottom) + 5.5rem);
    left: 1rem;
  }
  .fab-trigger { width: 48px; height: 48px; }
  .fab-trigger-icon { width: 20px; height: 20px; }
}

/* RTL: open the language popup to the LEFT of the pill. */
html[dir="rtl"] .fab-lang-popup {
  left: auto; right: calc(100% + 0.5rem);
  transform: translateY(50%) translateX(4px);
}
html[dir="rtl"] .fab-item-lang[data-open="true"] .fab-lang-popup {
  transform: translateY(50%) translateX(0);
}

/* ─── Spotlight blob (decorative SVG, desktop only) ─── */
.spotlight {
  pointer-events: none;
  position: absolute; z-index: 1;
  top: -40px; left: 0;
  height: 169%; width: 138%;
  opacity: 0;
  animation: spotlight 2s ease 0.75s 1 forwards;
}
@media (min-width: 768px) { .spotlight { left: 15rem; top: -5rem; width: 84%; } }
@keyframes spotlight {
  0%   { opacity: 0; transform: translate(-72%, -62%) scale(0.5); }
  100% { opacity: 1; transform: translate(-50%, -40%) scale(1); }
}

/* ─── Cursor halo (desktop, JS positions on mousemove) ─── */
.spotlight-cursor {
  pointer-events: none;
  position: absolute; z-index: 2;
  width: 300px; height: 300px;
  border-radius: 50%;
  opacity: 0;
  background: radial-gradient(circle at center, rgba(255,255,255,0.9), rgba(255,255,255,0.4) 40%, transparent 80%);
  filter: blur(40px);
  transform: translate3d(-9999px, -9999px, 0);
  transition: opacity 200ms ease;
}
@media (max-width: 767px) { .spotlight-cursor { display: none; } }

/* ─── Hero grid (two-column on desktop, hidden on mobile) ─── */
.hero-grid {
  position: relative; z-index: 1;
  width: 100%; height: 100%;
  max-width: 1600px; margin: 0 auto;
  padding: 1.5rem 1rem 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 2.5rem;
}
@media (min-width: 768px) {
  .hero-grid { padding: 2rem 2rem 0; flex-direction: row; align-items: stretch; gap: 3rem; }
}

.hero-text {
  position: relative; z-index: 10;
  flex: 0 0 auto;
  display: flex; flex-direction: column; align-items: flex-start;
  align-self: flex-start;
  padding: 3.5rem 0.75rem 0;
  text-align: left;
}
@media (min-width: 768px) { .hero-text { padding: 7rem 2.5rem 0; height: 100%; justify-content: flex-start; } }
@media (min-width: 1024px) { .hero-text { padding: 8rem 4rem 0; } }

.hero-text h1 {
  font-weight: 700;
  margin: 0 0 1rem;
  padding: 0.5rem 0;
  line-height: 1.4;
  font-size: clamp(2.25rem, 5vw, 4.5rem);
  background: linear-gradient(to bottom, #fafafa, #a3a3a3);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.hero-text p {
  font-size: 1rem;
  color: rgba(229,229,229,0.95);
  max-width: 26rem;
  line-height: 1.65;
  margin: 0;
}
@media (min-width: 768px) {
  .hero-text p { font-size: 1.125rem; max-width: 30rem; }
}
@media (min-width: 1024px) { .hero-text p { font-size: 1.25rem; } }

/* Right column for the 3D scene. Matches React's `flex-1` + bleed:
 * on desktop the canvas wrapper extends 8% beyond left/right and 2rem
 * below to reach past the page edges — that's the framing the Spline
 * scene was composed for. */
.hero-scene {
  flex: 1 1 0;
  position: relative;
  width: 100%;
  height: 46vh;
  align-self: flex-end;
}
@media (min-width: 640px) { .hero-scene { height: 54vh; } }
@media (min-width: 768px) { .hero-scene { height: 100%; } }

.hero-scene-bleed {
  position: absolute; inset: 0;
}
@media (min-width: 768px) {
  .hero-scene-bleed { left: -8%; right: -8%; bottom: -2rem; }
}

.hero-scene-bleed #spline-canvas {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  display: block;
  background: transparent;
}

/* Hide the whole hero on mobile — chat goes full-bleed. */
@media (max-width: 767px) { .hero-grid { display: none; } }

/* ─── Owner bar (only on a link the panel composed: ?back=panel|signup) ─── */
/* Above the loading/error overlays (z 50): the way back must never be the
   thing that gets covered. The root is pushed down by the bar's height so
   the chat, the mobile header and the overlays all start below it. */
:root { --owner-bar-h: 52px; }
.owner-bar {
  position: fixed; top: 0; left: 0; right: 0; z-index: 60;
  box-sizing: border-box; height: var(--owner-bar-h);
  display: flex; align-items: center; justify-content: center; gap: 0.75rem;
  padding: 0 1rem;
  background: var(--accent, #f7803c); color: #fff;
  font-size: 0.9rem; line-height: 1.25;
  box-shadow: 0 1px 0 rgba(0,0,0,0.12);
}
.owner-bar-text { opacity: 0.95; }
.owner-bar-btn {
  display: inline-flex; align-items: center;
  padding: 6px 12px; border-radius: 999px;
  background: #fff; color: var(--accent, #f7803c);
  font-weight: 600; text-decoration: none; white-space: nowrap;
}
.owner-bar-btn:hover { background: #fff3ea; }
#chat-root.has-owner-bar {
  margin-top: var(--owner-bar-h);
  height: calc(100vh - var(--owner-bar-h));
  min-height: calc(100svh - var(--owner-bar-h));
}
@media (max-width: 767px) {
  :root { --owner-bar-h: calc(env(safe-area-inset-top) + 76px); }
  .owner-bar { flex-direction: column; gap: 6px; padding-top: env(safe-area-inset-top); font-size: 0.85rem; text-align: center; }
}

/* ─── Mobile header (hidden on desktop) ─── */
.mobile-header {
  display: none;
  position: absolute; top: 0; left: 0; right: 0; z-index: 20;
  background: rgba(0,0,0,0.55);
  -webkit-backdrop-filter: blur(20px); backdrop-filter: blur(20px);
  padding: calc(env(safe-area-inset-top) + 14px) 1rem 14px;
  box-shadow: inset 0 -1px 0 rgba(255,255,255,0.06);
  align-items: center; gap: 0.75rem;
}
@media (max-width: 767px) { .mobile-header { display: flex; } }

.mobile-avatar {
  position: relative; width: 2.5rem; height: 2.5rem;
  flex-shrink: 0; border-radius: 50%; overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  background: #000;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,0.14), 0 1px 6px rgba(0,0,0,0.45);
}
.mobile-avatar span {
  position: absolute; font-size: 12.5px; font-weight: 600;
  letter-spacing: 0.02em; color: rgba(255,255,255,0.9);
}
.mobile-avatar img { position: relative; width: 100%; height: 100%; object-fit: cover; }

.mobile-titles { min-width: 0; flex: 1; }
.mobile-titles h1 {
  font-size: 1rem; font-weight: 600; line-height: 1.15;
  letter-spacing: -0.01em; margin: 0; color: #fff;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.mobile-status {
  margin: 0.125rem 0 0;
  display: flex; align-items: center; gap: 0.375rem;
  font-size: 11.5px; line-height: 1.2; letter-spacing: 0.01em;
  color: rgba(163,163,163,1);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.status-dot { position: relative; display: inline-flex; width: 0.375rem; height: 0.375rem; flex-shrink: 0; }
/* A pulsing green "online" beside a page that has stopped answering is a
   claim we can no longer make, so the light goes out with the composer. */
.is-unavailable .status-dot { display: none; }
.status-dot-pulse {
  position: absolute; inset: 0; border-radius: 50%;
  background: rgba(52,211,153,0.6);
  animation: ping 1s cubic-bezier(0, 0, 0.2, 1) infinite;
}
.status-dot-core {
  position: relative; width: 0.375rem; height: 0.375rem;
  border-radius: 50%; background: rgb(52,211,153);
}
@keyframes ping { 75%, 100% { transform: scale(2); opacity: 0; } }

/* ─── Chat overlay (centered glass card on desktop, full-bleed mobile) ─── */
.chat-overlay {
  position: absolute; inset: 0; z-index: 30;
  display: flex; align-items: center; justify-content: center;
  padding: 0 1rem;
  pointer-events: none;
}
.chat-stack {
  pointer-events: auto;
  width: 100%; max-width: 36rem;
  display: flex; flex-direction: column; gap: 1rem;
}

.messages-frame {
  position: relative; width: 100%;
  height: 58vh; min-height: 42vh;
  overflow: hidden;
  border-radius: 1.5rem;
}
@media (min-width: 768px) { .messages-frame { height: 60vh; } }

.messages-scroll {
  position: absolute; inset: 0;
  overflow-y: auto;
  -ms-overflow-style: none; scrollbar-width: none;
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, black 8%, black 100%);
          mask-image: linear-gradient(to bottom, transparent 0%, black 8%, black 100%);
}
.messages-scroll::-webkit-scrollbar { display: none; }

.messages-list {
  min-height: 100%;
  display: flex; flex-direction: column; justify-content: flex-end;
  gap: 0.75rem;
  padding: 2rem 0.75rem 1.5rem;
}

/* Chat bubbles */
.msg {
  font-size: 0.95rem; line-height: 1.55;
  max-width: 90%;
  padding: 0.75rem 1rem;
  border-radius: 1rem;
  border: 1px solid rgba(255,255,255,0.1);
  box-shadow: 0 10px 30px -10px rgba(0,0,0,0.45);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  animation: msg-rise 220ms cubic-bezier(0.2, 0.7, 0.2, 1);
  word-wrap: break-word; overflow-wrap: anywhere;
}
@media (min-width: 640px) { .msg { max-width: 80%; font-size: 1rem; } }

.msg.user {
  margin-left: auto;
  background: rgba(255,255,255,0.15);
  color: #fff;
  text-align: left;
  white-space: pre-wrap;
}
.msg.ai {
  margin-right: auto;
  background: rgba(0,0,0,0.3);
  color: rgba(255,255,255,0.95);
}
@keyframes msg-rise {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Empty state suggestions */
.empty-state { display: flex; flex-direction: column; gap: 1rem; padding: 0.5rem 0.25rem 0; }
/* An author `display` beats the UA sheet's `[hidden] { display: none }` no
   matter the specificity, so the line above kept the chips on screen for
   the whole conversation — and, worse, kept four one-tap questions live on
   a page that has stopped answering. Restate the rule for this element. */
.empty-state[hidden] { display: none; }
.suggestion-chips { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 0.5rem; }
.suggestion-chips button {
  width: 100%; text-align: left;
  border-radius: 1rem; padding: 0.75rem 1rem;
  border: 1px solid rgba(255,255,255,0.08);
  background: rgba(255,255,255,0.03);
  color: rgba(255,255,255,0.9);
  font-size: 0.92rem; line-height: 1.4;
  cursor: pointer;
  transition: background 150ms ease;
  opacity: 0;
  animation: chip-rise 320ms cubic-bezier(0.2, 0.7, 0.2, 1) both;
}
.suggestion-chips button:hover { background: rgba(255,255,255,0.06); }
.suggestion-chips button:active { background: rgba(255,255,255,0.08); }
@keyframes chip-rise {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Typing dots (shown while AI bubble is empty during streaming) */
.typing-dots { display: inline-flex; align-items: center; gap: 0.25rem; padding: 0.375rem 0.125rem; }
.typing-dots span {
  width: 0.375rem; height: 0.375rem; border-radius: 50%;
  background: rgba(255,255,255,0.6);
  animation: typing-dot 1.2s ease-in-out infinite;
}
.typing-dots span:nth-child(1) { animation-delay: -0.32s; }
.typing-dots span:nth-child(2) { animation-delay: -0.16s; }
@keyframes typing-dot {
  0%, 80%, 100% { transform: translateY(0); opacity: 0.4; }
  40%           { transform: translateY(-3px); opacity: 1; }
}

/* ─── Markdown content inside AI bubbles ─── */
.msg.ai p { margin: 0; }
.msg.ai p + p { margin-top: 0.75rem; }
.msg.ai ul, .msg.ai ol { margin: 0.5rem 0; padding-left: 1.25rem; display: flex; flex-direction: column; gap: 0.25rem; }
.msg.ai ul { list-style: disc; }
.msg.ai ol { list-style: decimal; }
.msg.ai li { line-height: 1.625; }
.msg.ai h1, .msg.ai h2, .msg.ai h3 {
  font-size: 1rem; font-weight: 600;
  margin: 0.75rem 0 0.5rem;
}
.msg.ai h3 { font-size: 0.9rem; }
.msg.ai strong { font-weight: 600; }
.msg.ai em { font-style: italic; }
.msg.ai code {
  border-radius: 0.25rem;
  background: rgba(255,255,255,0.1);
  padding: 0.1rem 0.3rem;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.9em;
}
.msg.ai pre {
  margin: 0.5rem 0; overflow-x: auto;
  border-radius: 0.75rem;
  border: 1px solid rgba(255,255,255,0.1);
  background: rgba(0,0,0,0.3);
  padding: 0.75rem;
}
.msg.ai pre code { background: transparent; padding: 0; }
.msg.ai blockquote {
  margin: 0.5rem 0; padding-left: 0.75rem;
  border-left: 2px solid rgba(255,255,255,0.2);
  color: rgba(255,255,255,0.8);
}
.msg.ai a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-color: rgba(255,255,255,0.4);
}
.msg.ai a:hover { text-decoration-color: #fff; }

/* ─── "Not taking questions" notice ───
   Sits between the transcript and the composer and stays put once shown.
   Deliberately quieter than a chat bubble — flat, centered, no entrance
   animation: it is the page's status, not something the twin said. */
.chat-notice {
  width: 100%; max-width: 36rem; margin: 0 auto;
  border-radius: 1rem;
  border: 1px solid rgba(255,255,255,0.1);
  background: rgba(0,0,0,0.3);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  padding: 0.875rem 1.125rem;
  text-align: center;
}
/* Stated explicitly for the same reason as `.empty-state[hidden]`: nothing
   here sets `display`, so the UA rule works today, and this keeps it
   working if someone later reaches for flex. */
.chat-notice[hidden] { display: none; }
.chat-notice-title {
  margin: 0;
  font-size: 0.95rem; line-height: 1.5;
  color: rgba(255,255,255,0.95);
}
.chat-notice-body {
  margin: 0.25rem 0 0;
  font-size: 0.85rem; line-height: 1.5;
  color: rgba(255,255,255,0.6);
}

/* ─── Composer ─── */
.composer {
  position: relative;
  max-width: 36rem; margin: 0 auto;
  width: 100%;
}
.composer textarea {
  width: 100%;
  background: rgba(0,0,0,0.3);
  border: 1px solid rgba(255,255,255,0.15);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  color: #fff;
  border-radius: 1.5rem;
  padding: 1rem 3rem 1rem 1.5rem;
  font-size: 16px; /* iOS: prevent zoom on focus */
  line-height: 1.3;
  resize: none;
  min-height: 3.25rem;
  max-height: 12rem;
  outline: none;
  font-family: inherit;
  -ms-overflow-style: none; scrollbar-width: none;
}
.composer textarea::-webkit-scrollbar { display: none; }
.composer textarea::placeholder { color: rgba(255,255,255,0.55); }
.composer textarea:focus { border-color: rgba(255,255,255,0.3); }
.composer textarea:disabled {
  opacity: 0.45; cursor: not-allowed;
  -webkit-text-fill-color: rgba(255,255,255,0.55); /* iOS greys it further */
}

.composer button {
  position: absolute; right: 0.6rem; top: 50%;
  transform: translateY(-50%);
  border: 0; cursor: pointer;
  width: 2rem; height: 2rem;
  border-radius: 0.75rem;
  display: flex; align-items: center; justify-content: center;
  background: rgba(255,255,255,0.1);
  color: #fff;
  transition: background 150ms ease, opacity 150ms ease;
}
.composer button:hover:not(:disabled) { background: rgba(255,255,255,0.2); }
.composer button:disabled { opacity: 0.3; cursor: not-allowed; }
.composer button .send-spinner { display: none; }
.composer button.sending .send-icon { display: none; }
.composer button.sending .send-spinner {
  display: block; width: 1rem; height: 1rem;
  border: 2px solid rgba(255,255,255,0.3);
  border-top-color: #fff;
  border-radius: 50%;
  animation: spin 700ms linear infinite;
}
.send-icon { width: 1rem; height: 1rem; }

/* ─── Mobile-specific overrides: composer sticks to bottom, messages
   fill above ─── */
@media (max-width: 767px) {
  .chat-overlay { padding: 0; align-items: stretch; }
  .chat-stack {
    max-width: none; gap: 0;
    padding-top: calc(env(safe-area-inset-top) + 4.25rem); /* clear header */
    padding-bottom: calc(env(safe-area-inset-bottom) + 0.75rem);
    height: 100%;
  }
  .messages-frame {
    flex: 1 1 auto; height: auto; min-height: 0;
    border-radius: 0;
  }
  .messages-scroll {
    -webkit-mask-image: linear-gradient(to bottom, transparent 0%, black 6%, black 100%);
            mask-image: linear-gradient(to bottom, transparent 0%, black 6%, black 100%);
  }
  .messages-list { padding: 1rem 0.875rem 1rem; }
  /* .chat-stack drops its gap on mobile, so the notice carries its own
     breathing room and squares off against the full-bleed composer. */
  .chat-notice {
    max-width: none;
    border-radius: 0.875rem;
    margin: 0 0.75rem;
    padding: 0.75rem 1rem;
  }
  .composer {
    padding: 0.75rem 0.75rem 0;
    background: rgba(0,0,0,0.85);
    -webkit-backdrop-filter: blur(20px); backdrop-filter: blur(20px);
    box-shadow: inset 0 1px 0 rgba(255,255,255,0.06);
  }
}

/* Shared keyframes */
@keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }

/* ── "Download CV" — present only when the owner's plan includes it ─── */
.cv-download {
  display: inline-flex; align-items: center; gap: 8px;
  margin-top: 1.2rem; padding: 10px 18px;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.28);
  color: #fafafa; text-decoration: none;
  font-size: 0.95rem; font-weight: 600;
  background: rgba(255, 255, 255, 0.08);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  transition: background 0.15s ease, border-color 0.15s ease;
}
.cv-download:hover {
  background: rgba(255, 255, 255, 0.16);
  border-color: rgba(255, 255, 255, 0.45);
}
.mobile-cv-download {
  margin-inline-start: auto;
  display: inline-flex; align-items: center; justify-content: center;
  width: 38px; height: 38px; flex-shrink: 0;
  border-radius: 12px;
  border: 1px solid rgba(255, 255, 255, 0.25);
  color: #fafafa;
  background: rgba(255, 255, 255, 0.08);
}
/* The display rules above would defeat the `hidden` attribute. */
.cv-download[hidden], .mobile-cv-download[hidden] { display: none; }
