/* ============================================================
   Sage Beta — stylesheet
   Tokens are lifted verbatim from the HypnoThoughts / Sage design
   system (project 60484d90). Components below are hand-rolled to
   match the React primitives without pulling in the bundle.

   The one rule that governs everything: this is ONE material,
   molded. Elements rise out of the canvas or sink into it. Depth
   comes from shadow, never from a border.
   ============================================================ */

@import url('https://fonts.googleapis.com/css2?family=Figtree:wght@300;400;500;600;700;800&family=Space+Mono:wght@400;700&display=swap');

/* ── Color ───────────────────────────────────────────────── */
:root {
  /* Gold · The Hive */
  --gold-100:#f6ecca; --gold-200:#ecd99a; --gold-300:#ddc06a;
  --gold-400:#cba63f; --gold-500:#b68f2c; --gold-600:#967122; --gold-700:#6f531a;
  --gold-glow:#e4c766; --gold-deep:#9c7c2e;

  /* Sage · The Signal */
  --sage-100:#eef6df; --sage-200:#dcedbf; --sage-300:#bfdd8d;
  --sage-400:#a3c765; --sage-500:#85a84a; --sage-600:#6b8a3a; --sage-700:#4f672b;
  --sage-glow:#c3e37e;

  /* Silver · Sidecars */
  --silver-100:#f2f4f7; --silver-200:#dfe3e9; --silver-300:#c4cad3;
  --silver-400:#a7aeb9; --silver-500:#878e9a; --silver-600:#666d78;
  --silver-glow:#e6eaef; --silver-deep:#8b929b;

  /* Blue · The Field */
  --blue-100:#dbe6f0; --blue-200:#a9c1d8; --blue-300:#6f92b3;
  --blue-400:#3f6488; --blue-500:#2b4a68; --blue-600:#1a3450;
  --blue-700:#10233b; --blue-900:#0a1626;

  /* Neutral */
  --ink-900:#1a1f27; --ink-800:#2b323d; --ink-700:#434c59; --ink-600:#5d6675;
  --ink-500:#7b8494; --ink-400:#9aa3b2; --ink-300:#bcc3ce; --ink-200:#d6dbe2;
  --ink-100:#e8ebf0; --ink-050:#f1f3f6; --white:#ffffff;

  /* Light mode — cool neumorphic clay */
  --canvas:#e6e9ef;
  --surface:#e6e9ef;
  --surface-sunk:#e2e5ec;
  --surface-hex-gold:linear-gradient(145deg,#e4c766,#b68f2c);
  --surface-hex-blue:linear-gradient(145deg,#6f92b3,#2b4a68);
  --surface-hex-silver:linear-gradient(145deg,#eef0f3,#b6bcc6);

  --shadow-light:#ffffff;
  --shadow-dark:#c2c7d1;

  --text-strong:var(--ink-900);
  --text-body:var(--ink-700);
  --text-muted:var(--ink-500);
  --text-faint:var(--ink-400);
  --text-on-gold:#3a2c07;
  --text-on-blue:#eaf1f8;

  --accent:var(--gold-400);
  --accent-strong:var(--gold-500);
  --signal:var(--sage-500);
  --signal-glow:var(--sage-glow);
  --edge:var(--silver-500);

  --line:rgba(70,80,100,0.10);
  --line-soft:rgba(70,80,100,0.06);

  --success:#4f9e4a; --warning:var(--gold-500); --danger:#c65a52; --info:var(--blue-400);
  --ring:rgba(143,194,71,0.55);

  /* Sage's turn is the one sanctioned large fill — the dusty swatch green, not
     a --sage-* ramp stop, which runs hotter than the design language allows.
     Ink is olive rather than --text-body: cool grey on a warm green reads
     muddy. Glow is a no-op here and only lights up in dark. */
  --bubble-sage:#ccd7bc;
  --bubble-sage-ink:#313d24;
  --bubble-sage-glow:0 0 0 rgba(0,0,0,0);
}

[data-theme="dark"] {
  --canvas:#0d1a2b;
  --surface:#12233a;
  --surface-sunk:#0e1c30;
  --surface-hex-gold:linear-gradient(145deg,#e4c766,#9c7c2e);
  --surface-hex-blue:linear-gradient(145deg,#3f6488,#10233b);
  --surface-hex-silver:linear-gradient(145deg,#c4cad3,#6a717c);

  --shadow-light:#1a3252;
  --shadow-dark:#060f1c;

  --text-strong:#f2f6fb;
  --text-body:#c3d0de;
  --text-muted:#8296ac;
  --text-faint:#5f7089;
  --text-on-gold:#2a2005;
  --text-on-blue:#eaf1f8;

  --accent:var(--gold-300);
  --accent-strong:var(--gold-400);
  --signal:var(--sage-glow);
  --signal-glow:var(--sage-glow);
  --edge:var(--silver-300);

  --line:rgba(180,200,225,0.12);
  --line-soft:rgba(180,200,225,0.07);

  --success:#6fca66; --warning:var(--gold-300); --danger:#e08078; --info:var(--blue-300);
  --ring:rgba(168,224,76,0.6);

  --bubble-sage:#1c2b23;
  --bubble-sage-ink:#cfe3b4;
  --bubble-sage-glow:0 0 18px rgba(154,173,131,0.20);
}

/* ── Typography ──────────────────────────────────────────── */
:root {
  --font-sans:'Figtree', ui-sans-serif, system-ui, -apple-system, sans-serif;
  --font-mono:'Space Mono', ui-monospace, 'SFMono-Regular', monospace;

  --fw-light:300; --fw-regular:400; --fw-medium:500;
  --fw-semibold:600; --fw-bold:700; --fw-black:800;

  --fs-h1:2.5rem; --fs-h2:1.875rem; --fs-h3:1.5rem; --fs-h4:1.25rem;
  --fs-lg:1.125rem; --fs-body:1rem; --fs-sm:0.875rem; --fs-xs:0.75rem;
  --fs-eyebrow:0.75rem;

  --lh-tight:1.05; --lh-snug:1.2; --lh-normal:1.5; --lh-relaxed:1.65;
  --ls-tight:-0.02em; --ls-normal:0; --ls-wide:0.04em; --ls-eyebrow:0.22em;

  /* Shape — soft and generous, per the design system */
  --radius-sm:10px; --radius-md:14px; --radius-lg:20px; --radius-xl:28px;

  --ease-standard:cubic-bezier(0.4,0,0.2,1);
  --ease-out:cubic-bezier(0.16,1,0.3,1);
  --dur-fast:140ms; --dur-normal:220ms; --dur-slow:360ms;
}

/* ── Elevation ───────────────────────────────────────────── */
/* Redeclared under [data-theme="dark"] because var() substitution resolves
   where a property is DECLARED — a :root-only definition would permanently
   bake in the light-mode shadow poles. */
:root, [data-theme="dark"] {
  --elev-1: 3px 3px 6px var(--shadow-dark), -3px -3px 6px var(--shadow-light);
  --elev-2: 6px 6px 12px var(--shadow-dark), -6px -6px 12px var(--shadow-light);
  --elev-3: 10px 10px 22px var(--shadow-dark), -10px -10px 22px var(--shadow-light);
  --elev-4: 16px 16px 34px var(--shadow-dark), -12px -12px 28px var(--shadow-light);
  --elev-inset-sm: inset 2px 2px 5px var(--shadow-dark), inset -2px -2px 5px var(--shadow-light);
  --elev-inset: inset 4px 4px 9px var(--shadow-dark), inset -4px -4px 9px var(--shadow-light);
  --elev-inset-lg: inset 6px 6px 14px var(--shadow-dark), inset -6px -6px 14px var(--shadow-light);
  --elev-flat: 2px 2px 4px var(--shadow-dark), -2px -2px 4px var(--shadow-light);
  --glow-signal: 0 0 0 1px rgba(143,194,71,0.25), 0 0 16px rgba(168,224,76,0.45);
  --glow-gold: 0 0 20px rgba(228,199,102,0.40);
}

/* ── Base ────────────────────────────────────────────────── */
* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  overscroll-behavior-y: none;
}

body {
  background: var(--canvas);
  color: var(--text-body);
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  line-height: var(--lh-relaxed);
  -webkit-font-smoothing: antialiased;
  /* Installed PWAs get no browser chrome — text selection on taps reads as a bug */
  -webkit-tap-highlight-color: transparent;
}

button { font-family: inherit; }

:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px var(--ring);
}

/* Scrollbars stay out of the material */
::-webkit-scrollbar { width: 0; height: 0; }

/* ── App frame ───────────────────────────────────────────── */
/* env(safe-area-inset-*) keeps content clear of the notch and home
   indicator once installed to the home screen. */
#app {
  height: 100vh;  /* fallback for browsers without dvh support */
  height: 100dvh;
  width: 100%;
  max-width: 560px;   /* mobile / narrow: full-width vertical column */
  margin: 0 auto;
  position: relative;
  overflow: hidden;
  background: var(--canvas);
}

/* Desktop: let Sage go wide — up to 95% of the container (fills a CF2 embed
   instead of sitting in a 560px column). Mobile stays vertical via the base
   rule above. Breakpoint responds to the iframe width when embedded. */
@media (min-width: 900px) {
  #app {
    max-width: 95%;
  }
}

.screen {
  position: absolute;
  inset: 0;
  display: none;
  flex-direction: column;
}
.screen.active { display: flex; }

.pad-top { padding-top: calc(env(safe-area-inset-top, 0px) + 22px); }
.pad-bottom { padding-bottom: calc(env(safe-area-inset-bottom, 0px) + 16px); }

/* ── Hexicon — polished material tile, never marked ──────── */
.hexicon {
  flex-shrink: 0;
  clip-path: polygon(25% 5%, 75% 5%, 100% 50%, 75% 95%, 25% 95%, 0% 50%);
  display: block;
}
.hexicon--gold   { background: var(--surface-hex-gold); }
.hexicon--blue   { background: var(--surface-hex-blue); }
.hexicon--silver { background: var(--surface-hex-silver); }

/* ── Eyebrow ─────────────────────────────────────────────── */
.eyebrow {
  font-family: var(--font-mono);
  font-size: var(--fs-eyebrow);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--signal);
  font-weight: var(--fw-regular);
}
.eyebrow--gold   { color: var(--accent); }
.eyebrow--muted  { color: var(--text-muted); }
.eyebrow--silver { color: var(--edge); }

/* ── Buttons ─────────────────────────────────────────────── */
.btn {
  border: none;
  cursor: pointer;
  height: 44px;
  padding: 0 22px;
  border-radius: var(--radius-md);
  font-weight: var(--fw-semibold);
  font-size: var(--fs-body);
  background: var(--surface);
  color: var(--text-body);
  box-shadow: var(--elev-2);
  transition: box-shadow var(--dur-fast) var(--ease-standard),
              transform var(--dur-fast) var(--ease-standard);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
}
.btn:active { box-shadow: var(--elev-inset-sm); }
.btn:disabled { opacity: 0.5; cursor: not-allowed; box-shadow: var(--elev-1); }
.btn--full { width: 100%; }
.btn--ghost { box-shadow: none; color: var(--text-muted); }
.btn--ghost:active { box-shadow: var(--elev-inset-sm); }
.btn--sm { height: 36px; padding: 0 14px; font-size: var(--fs-sm); }

/* Gold is the Hive core — reserved for the primary CTA. Used sparingly. */
.btn--primary {
  background: linear-gradient(145deg, var(--gold-glow), var(--gold-500));
  color: var(--text-on-gold);
  box-shadow: var(--elev-2);
}
.btn--send {
  background: linear-gradient(145deg, var(--sage-300), var(--sage-600));
  color: #fff;
}

.icon-btn {
  border: none;
  cursor: pointer;
  border-radius: 50%;
  background: var(--surface);
  color: var(--text-body);
  box-shadow: var(--elev-1);
  display: grid;
  place-items: center;
  flex-shrink: 0;
  transition: box-shadow var(--dur-fast) var(--ease-standard);
}
.icon-btn:active { box-shadow: var(--elev-inset-sm); }
.icon-btn--40 { width: 40px; height: 40px; }
.icon-btn--44 { width: 44px; height: 44px; }
.icon-btn--36 { width: 36px; height: 36px; }

/* ── Input — carved into the clay ────────────────────────── */
.input {
  width: 100%;
  border: none;
  background: var(--surface-sunk);
  box-shadow: var(--elev-inset);
  border-radius: var(--radius-md);
  padding: 12px 16px;
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  color: var(--text-body);
  min-height: 44px;
  resize: none;
}
.input::placeholder { color: var(--text-faint); }
.input:focus { outline: none; box-shadow: var(--elev-inset), 0 0 0 2px var(--ring); }

/* ── Card — a raised region of the canvas, not a box ─────── */
.card {
  background: var(--surface);
  border-radius: var(--radius-lg);
  box-shadow: var(--elev-2);
  padding: 18px;
}

/* ── Switch ──────────────────────────────────────────────── */
.switch {
  width: 52px; height: 30px;
  border-radius: 999px;
  border: none;
  cursor: pointer;
  background: var(--surface-sunk);
  box-shadow: var(--elev-inset-sm);
  position: relative;
  flex-shrink: 0;
  transition: background var(--dur-normal) var(--ease-standard);
}
.switch__dot {
  position: absolute;
  top: 4px; left: 4px;
  width: 22px; height: 22px;
  border-radius: 50%;
  background: var(--surface);
  box-shadow: var(--elev-1);
  transition: transform var(--dur-normal) var(--ease-out);
}
.switch[aria-checked="true"] { background: var(--sage-600); }
.switch[aria-checked="true"] .switch__dot { transform: translateX(22px); }

/* ── Chat header ─────────────────────────────────────────── */
.chat-header {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 16px;
  background: var(--canvas);
  position: relative;
  z-index: 2;
  flex-shrink: 0;
}
.chat-header__actions { display: flex; gap: 6px; flex-shrink: 0; }
.chat-header__actions .btn span { white-space: nowrap; }
@media (max-width: 360px) {
  /* Icon only once there's no room for labels -- aria-label still announces it. */
  .chat-header__actions .btn span { display: none; }
  .chat-header__actions .btn { padding: 0 10px; }
}
.chat-header__id {
  display: flex; align-items: center; gap: 10px;
  flex: 1; justify-content: center; min-width: 0;
}
.sage-dot {
  width: 32px; height: 32px; border-radius: 50%;
  background: var(--surface); box-shadow: var(--elev-1);
  display: grid; place-items: center; flex-shrink: 0;
}
.sage-dot i {
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--sage-400); box-shadow: 0 0 5px var(--sage-glow);
  display: block;
}
.chat-header__name {
  font-weight: var(--fw-bold); font-size: 16px;
  color: var(--text-strong); line-height: 1.25;
}
.chat-header__sub {
  font-size: 12px; color: var(--text-muted); line-height: 1.25;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* ── Message stream ──────────────────────────────────────── */
.stream {
  flex: 1;
  overflow-y: auto;
  padding: 18px 16px;
  display: flex;
  flex-direction: column;
  gap: 20px;
  -webkit-overflow-scrolling: touch;
}

.msg { display: flex; flex-direction: column; gap: 7px; max-width: 86%; }
.msg--assistant { align-self: flex-start; }
.msg--user { align-self: flex-end; }

.msg__meta { display: flex; align-items: center; gap: 8px; }
.msg--user .msg__meta { justify-content: flex-end; }
.msg__avatar {
  width: 20px; height: 20px; border-radius: 50%;
  background: var(--surface); box-shadow: var(--elev-1);
  display: grid; place-items: center; flex-shrink: 0;
}
.msg__avatar i {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--sage-400); box-shadow: 0 0 4px var(--sage-glow);
  display: block;
}
.msg__avatar--user {
  background: var(--ink-300); box-shadow: none;
  font-size: 10px; font-weight: var(--fw-bold); color: var(--text-strong);
}
.msg__you {
  font-family: var(--font-mono); font-size: 11px;
  letter-spacing: 0.18em; text-transform: uppercase; color: var(--text-faint);
}
.msg__bubble {
  background: var(--surface);
  border-radius: var(--radius-lg);
  padding: 16px 20px;
  box-shadow: var(--elev-2);
  color: var(--text-body);
  font-size: var(--fs-body);
  line-height: var(--lh-relaxed);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
/* Sage is raised out of the clay and carries the green; the member is pressed
   into it. The read is elevation first, colour second — so a long answer never
   depends on the fill alone to say who is speaking. */
.msg--assistant .msg__bubble {
  background: var(--bubble-sage);
  color: var(--bubble-sage-ink);
  box-shadow: var(--elev-2), var(--bubble-sage-glow);
}
.msg--user .msg__bubble {
  background: var(--surface-sunk);
  color: var(--text-body);
  box-shadow: var(--elev-inset-sm);
  padding: 14px 18px;
}

/* Citations — the corpus receipts. Always visible, never inferred. */
.cites {
  display: flex; flex-direction: column; gap: 6px;
  padding-left: 4px; margin-top: 2px;
}
.cite {
  font-size: 12px; color: var(--text-muted);
  display: flex; align-items: center; gap: 7px;
  line-height: 1.4;
}
.cite .hexicon { width: 12px; height: 14px; }
.cite { cursor: pointer; }
.cite:hover { color: var(--text-body); }
.cite--link {
  text-decoration: none;
  color: var(--text-muted);
}
.cite__label {
  min-width: 0;
  overflow-wrap: anywhere;
}
.cite__action {
  margin-left: auto;
  flex-shrink: 0;
  font-size: 14px;
  font-weight: var(--fw-semibold);
  color: #0f1115;
  background: var(--accent);
  padding: 7px 15px;
  border-radius: 9px;
  line-height: 1.25;
  white-space: nowrap;
}
.cite--link:hover .cite__action { background: var(--accent-strong); color: #0f1115; }
/* "Become a member" reads as an outlined variant, not the primary gold CTA. */
.cite__action--join {
  color: var(--accent);
  background: transparent;
  border: 1px solid var(--accent);
}
.cite--link:hover .cite__action--join { background: transparent; color: var(--accent-strong); border-color: var(--accent-strong); }

/* Feedback — thumbs + reason chips + optional correction text (2.2) */
.feedback { display: flex; flex-direction: column; gap: 6px; margin-top: 4px; padding-left: 4px; }
.feedback__votes { display: flex; gap: 8px; align-items: center; }
.feedback__vote {
  border: none; cursor: pointer; border-radius: 50%;
  width: 32px; height: 32px; display: grid; place-items: center;
  background: transparent; color: var(--text-muted);
  transition: color var(--dur-fast) var(--ease-standard), background var(--dur-fast) var(--ease-standard);
}
.feedback__vote svg { width: 18px; height: 18px; }
.feedback__vote:hover { color: var(--text-body); background: var(--surface-sunk); }
/* Sage green, not gold -- gold is reserved for the primary CTA elsewhere in
   this app. Filled icon (not just a color change) makes "selected" obvious
   at a glance, same idea as .switch[aria-checked="true"]'s solid fill. */
.feedback__vote.active { color: var(--sage-600); background: var(--surface-sunk); }
.feedback__vote.active svg { fill: currentColor; }
.feedback__chips { display: flex; flex-wrap: wrap; gap: 6px; }
.feedback__chip {
  border: none; cursor: pointer; border-radius: 999px;
  padding: 4px 10px; font-size: 11.5px; color: var(--text-muted);
  background: var(--surface-sunk); box-shadow: var(--elev-1);
}
.feedback__chip.active { color: #fff; background: var(--sage-600); }
.feedback__groups { display: flex; flex-direction: column; gap: 6px; }
.feedback__group-label {
  font-size: 10px; font-weight: var(--fw-bold); letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--text-faint);
}
.feedback__gate { display: flex; flex-direction: column; gap: 6px; }
.feedback__gate-question { font-size: 11.5px; color: var(--text-muted); }
.feedback__note-row { display: flex; gap: 6px; align-items: center; }
.feedback__note {
  flex: 1; min-width: 0; border: none; background: var(--surface-sunk); box-shadow: var(--elev-inset);
  border-radius: 8px; padding: 6px 10px; font-size: 12.5px;
  color: var(--text-body); font-family: var(--font-sans);
}
.feedback__note-send {
  border: none; cursor: pointer; border-radius: 8px; flex-shrink: 0;
  padding: 6px 12px; font-size: 12px; font-weight: var(--fw-semibold);
  color: var(--text-muted); background: var(--surface-sunk); box-shadow: var(--elev-1);
}
.feedback__note-send:active { box-shadow: var(--elev-inset-sm); }
.feedback__status { font-size: 11.5px; min-height: 14px; }
.feedback__status--ok { color: var(--text-muted); }
.feedback__status--error { color: var(--text-muted); }
.feedback__retry {
  border: none; background: none; padding: 0; font-size: 11.5px; text-decoration: underline;
  color: var(--accent-strong); cursor: pointer;
}

/* Typing indicator */
.typing { display: flex; gap: 5px; align-items: center; padding: 4px 2px; }
.typing i {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--sage-400);
  animation: typingPulse 1.3s ease-in-out infinite;
  display: block;
}
.typing i:nth-child(2) { animation-delay: 0.18s; }
.typing i:nth-child(3) { animation-delay: 0.36s; }
@keyframes typingPulse {
  0%,100% { opacity: 0.3; transform: scale(0.85); }
  50%     { opacity: 1;   transform: scale(1.1); }
}

/* Reassurance line under the typing dots on a long pre-first-token wait.
   Empty and taking no space until setTypingNote() fills it in. */
.typing-note {
  font-size: 12px;
  color: var(--text-muted);
  margin-top: 2px;
}

/* Caret shown while a reply is being paced onto the screen */
.caret {
  display: inline-block;
  width: 2px; height: 1em;
  background: var(--sage-500);
  vertical-align: text-bottom;
  animation: caretBlink 1s steps(1) infinite;
}
@keyframes caretBlink { 0%,49% { opacity: 1; } 50%,100% { opacity: 0; } }

/* ── Response mode toggle ────────────────────────────────── */
/* Per-message, not a persistent setting — sits right above the composer so
   both options are always visible, not tucked into settings. */
.mode-toggle {
  display: flex;
  gap: 4px;
  padding: 4px;
  margin: 0 16px 8px;
  background: var(--surface-sunk);
  border-radius: var(--radius-lg);
  box-shadow: var(--elev-inset-sm);
  flex-shrink: 0;
}
.mode-toggle__opt {
  flex: 1;
  border: none;
  background: transparent;
  color: var(--text-muted);
  font-family: var(--font-sans);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  padding: 8px 10px;
  border-radius: var(--radius-md);
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease-standard),
              color var(--dur-fast) var(--ease-standard),
              box-shadow var(--dur-fast) var(--ease-standard);
}
.mode-toggle__opt--active {
  background: var(--surface);
  color: var(--text-strong);
  box-shadow: var(--elev-flat);
}

/* ── Composer ────────────────────────────────────────────── */
.composer {
  display: flex;
  align-items: flex-end;
  gap: 10px;
  padding: 10px 16px 8px;
  background: var(--canvas);
  flex-shrink: 0;
}
.composer__disclaimer {
  margin: 0;
  padding: 0 16px calc(env(safe-area-inset-bottom, 0px) + 12px);
  font-size: 11px;
  line-height: 1.3;
  color: var(--text-muted);
  text-align: center;
  background: var(--canvas);
  flex-shrink: 0;
}
/* Two lines at rest, grows to roughly seven then scrolls. Scoped to the
   composer on purpose — .input is shared with the sign-in fields. */
.composer .input { flex: 1; min-width: 0; min-height: 68px; max-height: 200px; }

/* ── Drawer ──────────────────────────────────────────────── */
.overlay { position: absolute; inset: 0; z-index: 30; display: none; }
.overlay.active { display: block; }
.scrim {
  position: absolute; inset: 0;
  background: rgba(10,15,25,0.45);
  animation: scrimIn var(--dur-normal) var(--ease-standard);
}
@keyframes scrimIn { from { opacity: 0; } to { opacity: 1; } }

.drawer {
  position: absolute; top: 0; left: 0; bottom: 0;
  width: 86%; max-width: 330px;
  background: var(--canvas);
  box-shadow: 14px 0 40px rgba(0,0,0,0.28);
  display: flex; flex-direction: column;
  animation: drawerIn var(--dur-slow) var(--ease-out);
}
@keyframes drawerIn { from { transform: translateX(-100%); } to { transform: translateX(0); } }

.drawer__head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 18px 18px 14px;
  flex-shrink: 0;
}
.drawer__title { font-size: 20px; font-weight: var(--fw-bold); color: var(--text-strong); }
.drawer__body {
  flex: 1; overflow-y: auto;
  padding: 4px 14px calc(env(safe-area-inset-bottom, 0px) + 24px);
  display: flex; flex-direction: column; gap: 20px;
}

.convo-group { display: flex; flex-direction: column; gap: 8px; }

.convo {
  display: flex; align-items: center; gap: 12px;
  padding: 12px;
  border-radius: var(--radius-lg);
  background: transparent;
  border: none;
  cursor: pointer;
  text-align: left;
  width: 100%;
  color: inherit;
  font-family: inherit;
}
.convo[aria-current="true"] {
  background: var(--surface);
  box-shadow: var(--elev-inset-sm);
}
.convo .hexicon { width: 30px; height: 34px; }
.convo__text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.convo__title {
  font-weight: var(--fw-semibold); font-size: 14.5px; color: var(--text-strong);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.convo__preview {
  font-size: 12.5px; color: var(--text-muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.convo__time {
  font-size: 11px; color: var(--text-faint);
  font-family: var(--font-mono); flex-shrink: 0;
}

/* ── Sign-in ─────────────────────────────────────────────── */
.signin {
  flex: 1;
  display: flex; flex-direction: column;
  align-items: center; justify-content: flex-start;
  padding: 40px 28px calc(env(safe-area-inset-bottom, 0px) + 32px);
  gap: 22px;
  text-align: center;
}
.signin__mark { width: 84px; height: 92px; margin-bottom: 4px;
  background: url('/sage-mark.svg') center/contain no-repeat; }
.signin__title {
  font-size: var(--fs-h2); font-weight: var(--fw-semibold);
  color: var(--text-strong); letter-spacing: var(--ls-tight);
  line-height: var(--lh-snug); margin: 0;
}
.signin__body {
  font-size: var(--fs-sm); color: var(--text-muted);
  max-width: 34ch; margin: 0; line-height: var(--lh-relaxed);
}
.signin__form { width: 100%; display: flex; flex-direction: column; gap: 12px; }
.signin__note {
  font-size: 12px; color: var(--text-faint);
  max-width: 36ch; line-height: 1.5; margin: 0;
}
.signin__status {
  font-size: var(--fs-sm); line-height: var(--lh-relaxed);
  min-height: 1.4em; margin: 0;
}
.signin__status--ok { color: var(--signal); }
.signin__status--err { color: var(--danger); }

/* ── Settings ────────────────────────────────────────────── */
.settings-body {
  flex: 1; overflow-y: auto;
  padding: 6px 16px calc(env(safe-area-inset-bottom, 0px) + 40px);
  display: flex; flex-direction: column; gap: 18px;
}
.row { display: flex; align-items: center; justify-content: space-between; gap: 14px; }
.row__label { font-weight: var(--fw-semibold); font-size: 15px; color: var(--text-strong); }
.row__sub { font-size: 12.5px; color: var(--text-muted); margin-top: 2px; }

.avatar-lg {
  width: 52px; height: 52px; border-radius: 50%;
  background: linear-gradient(145deg, var(--gold-glow), var(--gold-500));
  display: grid; place-items: center;
  color: var(--text-on-gold); font-weight: var(--fw-bold); font-size: 18px;
  flex-shrink: 0;
}

.screen-head {
  display: flex; align-items: center; gap: 12px;
  padding: 16px; flex-shrink: 0;
}
.screen-head__title { font-size: 20px; font-weight: var(--fw-bold); color: var(--text-strong); }

/* ── Voice — coming soon ─────────────────────────────────── */
.voice {
  position: absolute; inset: 0; z-index: 40;
  background: #060f1c;
  display: none;
  flex-direction: column; align-items: center;
}
.voice.active { display: flex; }
.voice__top {
  width: 100%;
  display: flex; justify-content: flex-end;
  padding: calc(env(safe-area-inset-top, 0px) + 22px) 18px 0;
  flex-shrink: 0;
  position: relative; z-index: 2;
}
.voice__close {
  width: 40px; height: 40px; border-radius: 50%;
  border: none; cursor: pointer;
  background: rgba(255,255,255,0.08);
  color: rgba(255,255,255,0.75);
  display: grid; place-items: center;
}
.voice__mid {
  flex: 1; width: 100%;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  gap: 24px; position: relative; z-index: 2;
  padding: 0 32px;
}
/* Per design_handoff_voice_mode: flat, borderless, background and tile fill
   both #060f1c (deliberately identical — tiles are invisible, only the
   seams between them read). A framed/inset version was tried and rejected;
   keep it plain. Brightness is driven live by voiceLevel (see voice.js). */
.voice__hive {
  position: relative;
  width: 100%; height: 225px;
  background: #060f1c;
  overflow: hidden;
  filter: brightness(1);
  transition: filter 120ms linear;
}

/* Ambient light blobs drifting behind the grid — placed before the SVG in
   the DOM so normal stacking order keeps them behind the hex tiles/glow. */
.hive-light {
  position: absolute;
  margin-left: -45px;
  margin-top: -45px;
  border-radius: 50%;
  filter: blur(13px);
  background: radial-gradient(circle, rgba(120,240,110,0.4), rgba(90,220,90,0.1) 55%, rgba(90,220,90,0) 75%);
  animation: lightDrift 8s ease-in-out infinite;
}
@keyframes lightDrift {
  0%,100% { opacity: 0.55; transform: translate(0,0) scale(0.9); }
  33%     { opacity: 1;    transform: translate(10px,-8px) scale(1.15); }
  66%     { opacity: 0.7;  transform: translate(-8px,6px) scale(0.95); }
}
.voice__label {
  font-family: var(--font-mono); font-size: 12px;
  letter-spacing: 0.22em; text-transform: uppercase;
  color: rgba(220,230,210,0.6);
}
.voice__note {
  font-size: var(--fs-sm); color: rgba(255,255,255,0.55);
  text-align: center; max-width: 32ch; line-height: var(--lh-relaxed);
  margin: 0;
}
.voice__state {
  font-size: var(--fs-lg); color: rgba(255,255,255,0.9);
  font-weight: var(--fw-medium); text-align: center;
}
.voice__timer {
  font-family: var(--font-mono); font-size: 13px;
  letter-spacing: 0.12em; color: var(--sage-glow);
}
.voice__bottom {
  display: flex; flex-direction: column; align-items: center; gap: 12px;
  padding-bottom: calc(env(safe-area-inset-bottom, 0px) + 36px);
  flex-shrink: 0; position: relative; z-index: 2;
}
.voice__stop { color: rgba(255,255,255,0.75); height: 36px; padding: 0 16px; }
.voice__meter {
  display: flex; align-items: center; gap: 8px;
  font-size: 12px; color: rgba(255,255,255,0.55);
  font-family: var(--font-mono);
}

/* The mic is the one place the sage signal becomes a fill rather than a line —
   it is the live element on an otherwise dark screen. */
.voice-mic {
  width: 72px; height: 72px; border-radius: 50%;
  border: none; cursor: pointer;
  background: linear-gradient(145deg, var(--sage-400), var(--sage-600));
  color: #fff;
  display: grid; place-items: center;
  box-shadow: 0 0 0 0 rgba(168,224,76,0.55);
  transition: transform var(--dur-fast) var(--ease-standard),
              box-shadow var(--dur-normal) var(--ease-standard),
              background var(--dur-normal) var(--ease-standard);
}
.voice-mic:active { transform: scale(0.95); }
.voice-mic:disabled {
  background: rgba(255,255,255,0.09);
  color: rgba(255,255,255,0.35);
  cursor: not-allowed;
}
.voice-mic--rec {
  background: linear-gradient(145deg, #e0605a, #b3423d);
  animation: micPulse 1.6s ease-in-out infinite;
}
@keyframes micPulse {
  0%,100% { box-shadow: 0 0 0 0 rgba(224,96,90,0.5); }
  50%     { box-shadow: 0 0 0 14px rgba(224,96,90,0); }
}

/* Composer mic reflects voice availability without hiding the control */
#btn-voice.is-disabled { opacity: 0.4; }

/* ── Voice speed control ─────────────────────────────────── */
/* Beta ships one voice (Nova) with no picker — just a Slow/Medium/Fast
   segmented control, driven entirely by the backend's speed_presets. */
.speed-control {
  display: flex;
  background: var(--surface-sunk);
  box-shadow: var(--elev-inset-sm);
  border-radius: var(--radius-md);
  padding: 4px;
  gap: 4px;
}
.speed-tab {
  flex: 1;
  border: none; cursor: pointer;
  background: transparent;
  border-radius: var(--radius-sm);
  padding: 9px 0;
  font-family: var(--font-sans);
  font-weight: var(--fw-semibold);
  font-size: 13.5px;
  color: var(--text-muted);
  transition: background var(--dur-fast) var(--ease-standard),
              box-shadow var(--dur-fast) var(--ease-standard),
              color var(--dur-fast) var(--ease-standard);
}
.speed-tab--on {
  background: var(--surface);
  box-shadow: var(--elev-1);
  color: var(--signal);
}

/* ── Meter ───────────────────────────────────────────────── */
.meter {
  height: 10px; border-radius: 999px;
  background: var(--surface-sunk);
  box-shadow: var(--elev-inset-sm);
  overflow: hidden;
}
.meter__fill {
  height: 100%;
  background: linear-gradient(90deg, var(--sage-400), var(--sage-600));
  border-radius: 999px;
  transition: width var(--dur-slow) var(--ease-out);
}
.meter__value {
  font-family: var(--font-mono); font-size: 12px;
  color: var(--signal); letter-spacing: var(--ls-wide);
}
@keyframes hiveBreathe {
  0%,100% { opacity: 0.5; filter: drop-shadow(0 0 2px #6ee968) drop-shadow(0 0 4px #4fd94a); }
  50%     { opacity: 1;   filter: drop-shadow(0 0 5px #6ee968) drop-shadow(0 0 11px #4fd94a); }
}

/* ── Toast ───────────────────────────────────────────────── */
.toast {
  position: absolute;
  left: 50%; bottom: calc(env(safe-area-inset-bottom, 0px) + 90px);
  transform: translateX(-50%) translateY(12px);
  z-index: 60;
  background: var(--surface);
  box-shadow: var(--elev-3);
  border-radius: var(--radius-md);
  padding: 11px 18px;
  font-size: var(--fs-sm);
  color: var(--text-body);
  max-width: 84%;
  text-align: center;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--dur-normal) var(--ease-out),
              transform var(--dur-normal) var(--ease-out);
}
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }

.empty {
  color: var(--text-faint);
  font-size: var(--fs-sm);
  text-align: center;
  padding: 18px 8px;
  line-height: var(--lh-relaxed);
}

/* Respect the system preference for reduced motion — the neumorphic
   material still reads correctly without any of the animation. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}
