/* =========================================================
   ConBOT — tokens
========================================================= */

:root {
  /* Page vs. sidebar vs. white "card" surface — three distinct tiers */
  --page-bg: #fafaf9;
  --surface: #f4f4f5;
  --canvas: #ffffff;

  /* Text scale: primary / secondary / muted / placeholder */
  --ink: #18181b;
  --ink-2: #3f3f46;
  --ink-3: #52525b;
  --placeholder: #94a3b8;

  --hairline: #e4e4e7;
  --accent: #2563eb;
  --accent-ink: #ffffff;
  --accent-warm: #f97316;
  --accent-warm-ink: #ffffff;
  --bubble: #3b82f6;
  --code-bg: #f4f4f5;

  /* A distinct accent for the image generator, separate from chat's blue */
  --accent-image: #8a3ffc;
  --accent-image-ink: #ffffff;

  --bar-h: 52px;
  --col: 720px;

  --r-sm: 10px;
  --r-md: 12px;
  --r-lg: 24px;

  --composer-shadow: 0 1px 2px rgba(24, 24, 27, 0.04), 0 10px 30px rgba(24, 24, 27, 0.07);

  --ease: cubic-bezier(0.25, 0.1, 0.25, 1);
}

body.dark {
  --page-bg: #09090b;
  --surface: #18181b;
  --canvas: #1f1f23;
  --ink: #fafafa;
  --ink-2: #d4d4d8;
  --ink-3: #a1a1aa;
  --placeholder: #94a3b8;
  --hairline: #27272a;
  --accent: #3b82f6;
  --accent-ink: #000000;
  --accent-warm: #fb923c;
  --accent-warm-ink: #000000;
  --bubble: #3b82f6;
  --code-bg: #18181b;
  --accent-image: #a76bff;
  --accent-image-ink: #000000;
  --composer-shadow: 0 1px 2px rgba(0, 0, 0, 0.24), 0 12px 36px rgba(0, 0, 0, 0.36);
}

@media (prefers-color-scheme: dark) {
  body:not(.light) {
    --page-bg: #09090b;
    --surface: #18181b;
    --canvas: #1f1f23;
    --ink: #fafafa;
    --ink-2: #d4d4d8;
    --ink-3: #a1a1aa;
    --placeholder: #94a3b8;
    --hairline: #27272a;
    --accent: #3b82f6;
    --accent-ink: #000000;
    --bubble: #3b82f6;
    --code-bg: #18181b;
    --accent-image: #a76bff;
    --accent-image-ink: #000000;
    --composer-shadow: 0 1px 2px rgba(0, 0, 0, 0.24), 0 12px 36px rgba(0, 0, 0, 0.36);
  }
}

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

html, body {
  margin: 0;
  height: 100%;
}

body {
  transition: background-color 0.2s, color 0.2s;
  background: var(--page-bg);
  color: var(--ink);
  font-family: "Geist", "Noto Sans Devanagari", system-ui, sans-serif;
  font-size: 17px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

button, textarea { font: inherit; color: inherit; }
button { border: 0; background: none; cursor: pointer; }

:focus-visible {
  outline: 3px solid color-mix(in srgb, var(--accent) 40%, transparent);
  outline-offset: 2px;
  border-radius: 6px;
}

svg { fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }

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

/* =========================================================
   Top bar — translucent, hairline under
========================================================= */

.bar {
  position: fixed; inset: 0 0 auto 0; z-index: 20;
  height: var(--bar-h);
  background: color-mix(in srgb, var(--canvas) 72%, transparent);
  backdrop-filter: saturate(180%) blur(20px);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  border-bottom: 1px solid transparent;
  transition: border-color 0.3s var(--ease);
}

.bar.scrolled { border-bottom-color: var(--hairline); }

.bar-inner {
  max-width: var(--col);
  height: 100%;
  margin: 0 auto;
  padding: 0 22px;
  display: flex; align-items: center; justify-content: space-between;
}

.wordmark {
  font-size: 17px;
  font-weight: 600;
  letter-spacing: -0.015em;
  padding: 6px 0;
}

.ghost {
  width: 34px; height: 34px;
  display: grid; place-items: center;
  border-radius: 50%;
  color: var(--ink-2);
  transition: background 0.2s var(--ease), color 0.2s var(--ease);
}
.ghost:hover { background: var(--surface); color: var(--ink); }

.ic-moon { display: none; }
body.dark .ic-sun { display: none; }
body.dark .ic-moon { display: block; }
@media (prefers-color-scheme: dark) {
  body:not(.light) .ic-sun { display: none; }
  body:not(.light) .ic-moon { display: block; }
}

/* =========================================================
   Stage
========================================================= */

.stage {
  max-width: var(--col);
  margin: 0 auto;
  padding: calc(var(--bar-h) + 8px) 22px 0;
  min-height: 100%;
}

/* ===== Hero — centred "what do you want to know" home screen ===== */

.hero {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: calc(100vh - var(--bar-h));
  padding: 24px 0;
  text-align: center;
}

.hero-inner {
  width: 100%;
  max-width: var(--col);
  text-align: center;
}

.hero.gone { display: none; }
.hero-inner { margin: 0 auto; }

.ask-heading {
  margin: 0;
  font-size: 38px;
  font-weight: 600;
  letter-spacing: -0.025em;
  color: var(--ink);
  animation: rise 0.7s var(--ease) both;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
}

.ask-heading .emoji {
  font-size: 42px;
  line-height: 1;
  animation: chipIn 0.5s var(--ease) forwards;
  opacity: 0;
}

.ask-heading span {
  animation: chipIn 0.5s var(--ease) 0.1s forwards;
  opacity: 0;
  transform: translateY(4px);
}

.ask-heading::before {
  content: "👋";
  font-size: 42px;
  line-height: 1;
  color: var(--accent-warm);
  animation: chipIn 0.5s var(--ease) 0.2s forwards;
  opacity: 0;
}

.hero-inner .composer {
  max-width: var(--col);
  margin: 24px auto 0;
  text-align: left;
  animation: rise 0.7s var(--ease) 0.06s both;
}

.chips {
  margin: 24px auto 0;
  display: flex; flex-wrap: wrap; justify-content: center; gap: 12px;
  animation: rise 0.7s var(--ease) 0.1s both;
}

.chip {
  height: 44px;
  padding: 0 18px;
  display: inline-flex; align-items: center;
  font-size: 14px;
  color: var(--ink-2);
  background: var(--canvas);
  border: 1px solid var(--hairline);
  border-radius: 999px;
  transition: all 0.2s var(--ease-out);
  position: relative;
  overflow: hidden;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
  animation: chipIn 0.5s var(--ease) 0.3s forwards;
  opacity: 0;
}

.chip::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 3px;
  background: color-mix(in srgb, var(--accent) 30%, transparent);
  border-radius: 999px;
  opacity: 0;
  transition: opacity 0.2s var(--ease);
}

.chip:hover {
  color: var(--ink);
  border-color: color-mix(in srgb, var(--accent) 45%, var(--hairline));
  transform: translateY(-2px) scale(1.02);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
  background: color-mix(in srgb, var(--surface) 80%, var(--canvas));
}

.chip:hover::before {
  opacity: 0.4;
}

.chip:active {
  transform: translateY(1px) scale(0.98);
}

.chip:focus-visible {
  outline: 2px solid var(--accent-warm);
  outline-offset: 2px;
}

.chip.chip-accent {
  color: var(--accent-warm);
  border-color: var(--accent-warm);
}

.chip.chip-accent:hover {
  background: color-mix(in srgb, var(--accent-warm) 12%, transparent);
  color: var(--accent-warm-ink);
}
.chip:hover {
  color: var(--ink);
  border-color: color-mix(in srgb, var(--accent) 40%, var(--hairline));
  transform: translateY(-1px);
}

@keyframes rise {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: none; }
}

@keyframes chipIn {
  from { opacity: 0; transform: translateY(8px) scale(0.95); }
  to   { opacity: 1; transform: none; }
}

/* =========================================================
   Thread
========================================================= */

.thread {
  padding-bottom: 200px;
}

.turn { animation: rise 0.45s var(--ease) both; }

/* Claude/ChatGPT style: the question is not a chat bubble on the right —
   it's the heading of the answer that follows, left-aligned in the same
   column, set heavier than body text so the exchange still reads clearly. */
.turn.you {
  margin: 34px 0 0;
}

.text {
  max-width: 70ch;   /* readable line length, independent of the wider column */
}

.turn.you .text {
  font-size: 30px;
  font-weight: 600;
  letter-spacing: -0.015em;
  line-height: 1.25;
  color: var(--ink);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.turn.bot { margin: 14px 0 0; }

.turn.bot .text {
  font-size: 16px;
  line-height: 1.65;
}

.turn.bot .text > *:first-child { margin-top: 0; }
.turn.bot .text > *:last-child { margin-bottom: 0; }

/* First paragraph of an answer, when there is one — a one-line takeaway
   ahead of the rest of the prose. */
.turn.bot .text p.takeaway {
  font-size: 18px;
  font-weight: 700;
  line-height: 1.5;
}

.text p { margin: 0 0 14px; }
.text h2, .text h3 {
  font-size: 19px; font-weight: 600; letter-spacing: -0.015em;
  margin: 26px 0 10px;
}
.text ul, .text ol { margin: 0 0 14px; padding-left: 22px; }
.text li { margin: 5px 0; }
.text a { color: var(--accent); text-decoration: none; }
.text a:hover { text-decoration: underline; }
.text strong { font-weight: 600; }

.text code {
  font-family: "SF Mono", ui-monospace, Menlo, monospace;
  font-size: 14.5px;
  background: color-mix(in srgb, var(--ink) 5%, var(--code-bg));
  padding: 2px 6px;
  border-radius: 6px;
}

.text pre {
  background: color-mix(in srgb, var(--ink) 5%, var(--code-bg));
  border: 1px solid var(--hairline);
  border-radius: var(--r-md);
  padding: 16px 18px;
  overflow-x: auto;
  margin: 0 0 14px;
}
.text pre code { background: none; padding: 0; font-size: 14px; line-height: 1.55; }

/* ===== Row of quiet actions under an answer ===== */

.acts {
  display: flex; gap: 4px;
  margin-top: 10px;
  opacity: 0;
  transition: opacity 0.25s var(--ease);
}
.turn.bot:hover .acts, .acts:focus-within { opacity: 1; }

.act {
  font-size: 13px;
  color: var(--ink-2);
  padding: 5px 10px;
  border-radius: 8px;
}
.act:hover { background: var(--surface); color: var(--ink); }

/* ===== Sources ===== */

.sources {
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid var(--hairline);
  display: flex; flex-wrap: wrap; gap: 8px;
}

.source {
  display: inline-block;
  max-width: 300px;
  padding: 7px 13px;
  font-size: 13.5px;
  color: var(--ink-2);
  background: var(--surface);
  border-radius: 999px;
  text-decoration: none;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  transition: color 0.2s var(--ease);
}
.source:hover { color: var(--accent); }

/* ===== Thinking ===== */

.dots { display: flex; gap: 6px; padding: 8px 0; }
.dots i {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--ink-2);
  animation: pulse 1.3s var(--ease) infinite;
}
.dots i:nth-child(2) { animation-delay: 0.16s; }
.dots i:nth-child(3) { animation-delay: 0.32s; }

@keyframes pulse {
  0%, 60%, 100% { opacity: 0.3; transform: scale(0.7); }
  30% { opacity: 1; transform: scale(1.15); }
}

.waking {
  margin: 10px 0 0;
  font-size: 14px;
  color: var(--ink-2);
}

.notice {
  color: var(--ink-2);
  font-size: 16px;
}

/* =========================================================
   Skeleton loading states — shimmering placeholder lines
   shown while the first answer token streams in.
========================================================= */

.skeleton {
  background: linear-gradient(
    90deg,
    var(--surface) 25%,
    color-mix(in srgb, var(--ink) 8%, transparent) 50%,
    var(--surface) 75%
  );
  background-size: 200% 100%;
  animation: skeleton-pulse 1.4s ease infinite;
  border-radius: 6px;
}

.skeleton-line {
  height: 1.2em;
  width: 100%;
  margin: 0 0 10px;
}

.skeleton-line.short {
  width: 60%;
}

@keyframes skeleton-pulse {
  0% {
    background-position: 200% 0;
  }
  100% {
    background-position: -200% 0;
  }
}

/* =========================================================
   Code blocks — fenced code with copy button
========================================================= */

.code-block {
  position: relative;
  margin: 14px 0;
  border-radius: var(--radius-md);
  overflow: hidden;
  border: 1px solid var(--hairline);
  background: var(--code-bg);
}

.code-copy {
  position: absolute;
  top: 8px;
  right: 8px;
  z-index: 2;
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 6px;
  padding: 4px 8px;
  font-size: 12px;
  color: var(--ink-2);
  cursor: pointer;
  transition: all 0.15s var(--ease);
}

.code-copy:hover {
  background: color-mix(in srgb, var(--accent) 10%, var(--canvas));
  border-color: color-mix(in srgb, var(--accent) 30%, var(--hairline));
  color: var(--accent);
}

.code-copy:active {
  transform: scale(0.95);
}

.code-block pre {
  margin: 0;
  padding: 16px 18px 16px 18px;
  overflow-x: auto;
  background: none;
  border: none;
}

.code-block pre code {
  background: none;
  padding: 0;
  font-size: 14px;
  line-height: 1.55;
}

/* =========================================================
   Composer dock
========================================================= */

.dock-inner .composer { margin-top: 0; }

.dock {
  position: fixed; inset: auto 0 0 0; z-index: 20;
  animation: dockIn 0.5s var(--ease) both;
  padding: 14px 22px calc(16px + env(safe-area-inset-bottom));
  background: linear-gradient(to top,
    var(--canvas) 55%,
    color-mix(in srgb, var(--canvas) 0%, transparent));
}

.composer {
  max-width: var(--col);
  margin: 30px auto 0;
  position: relative;
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: 8px;
  padding: 7px 7px 7px 10px;
  background: var(--canvas);
  border: 1px solid var(--hairline);
  border-radius: var(--r-lg);
  box-shadow: var(--composer-shadow);
  transition: border-color 0.2s var(--ease), box-shadow 0.2s var(--ease);
}

.composer:focus-within {
  border-color: color-mix(in srgb, var(--accent) 55%, var(--hairline));
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--accent) 12%, transparent);
}

.composer textarea {
  flex: 1 1 0;
  min-width: 0;
  border: 0; background: none; resize: none;
  padding: 9px 0;
  max-height: calc(5 * 1.45em + 18px);   /* five rows, then it scrolls */
  line-height: 1.45;
  letter-spacing: -0.01em;
}
.composer textarea:focus { outline: none; }
.composer textarea::placeholder { color: var(--placeholder); }

.send {
  flex: none;
  width: 34px; height: 34px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--accent);
  color: var(--accent-ink);
  transition: background 0.2s var(--ease), color 0.2s var(--ease), transform 0.15s var(--ease);
}
.send:disabled {
  background: var(--surface);
  color: var(--ink-2);
  cursor: default;
}
.send:not(:disabled):active { transform: scale(0.92); }
.send.stop svg { stroke-width: 0; }

.fineprint {
  max-width: var(--col);
  margin: 9px auto 0;
  text-align: center;
  font-size: 12px;
  color: var(--ink-2);
}
.hero-fineprint { margin-top: 20px; }

/* =========================================================
   Small screens
========================================================= */

@media (max-width: 640px) {
  body { font-size: 16px; }
  .stage, .bar-inner { padding-left: 16px; padding-right: 16px; }
  .dock { padding-left: 16px; padding-right: 16px; }
  .turn.you .text { font-size: 24px; }
  .fineprint { font-size: 11px; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  .dots i { animation: none; opacity: 0.5; }
  .skeleton { animation: none; opacity: 0.6; }
}

/* =========================================================
   The one bold element
   Everything else on this page is quiet, so the identity lives in a
   single mark: two overlapping arcs beside the wordmark — two voices in
   conversation. It opens once on load and then holds still.
========================================================= */

.wordmark {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  transition: opacity 0.2s var(--ease);
}
.wordmark:hover { opacity: 0.72; }

.wordmark .mark {
  stroke: var(--accent);
  animation: open 0.9s var(--ease) 0.3s both;
}

@keyframes open {
  from { transform: scale(0); opacity: 0; }
  60%  { transform: scale(1.35); opacity: 1; }
  to   { transform: scale(1); opacity: 1; }
}

@keyframes dockIn {
  from { transform: translateY(14px); opacity: 0; }
  to   { transform: none; opacity: 1; }
}

/* Streamed text lands mid-word, so keep the block from jittering. */
.turn.bot .text { min-height: 1.5em; }

.thread { padding-bottom: 26px; }
body.chatting .thread { padding-bottom: 190px; }

/* =========================================================
   Devanagari needs more room than Latin at the same size
========================================================= */

:lang(hi), .text:has(> :not(:lang(en))) { line-height: 1.62; }

/* =========================================================
   Phone first — this is where most Indian users will open it
========================================================= */

@media (max-width: 640px) {

  .ask-heading { font-size: 28px; }

  /* Cheap Android GPUs drop frames on backdrop blur. Use a solid bar. */
  .bar, .dock {
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    background: var(--canvas);
  }

  .dock { padding-top: 10px; }
  body.chatting .thread { padding-bottom: 170px; }

  /* The composer is pinned into #dock before the first message too (see
     syncComposerDock() in app.js) — leave room so the heading/chips
     never sit behind it, and drop the hero's own fineprint since #dock
     already prints its own copy right under the pinned composer.
     justify-content switches to flex-start: centering is for the
     desktop group (heading+composer+chips together) — once the
     composer is pinned bottom, what's left is too short a block to
     centre in near-full-viewport height without floating in a big
     empty gap below the header. */
  .hero {
    justify-content: flex-start;
    padding-top: 48px;
    padding-bottom: 140px;
  }
  .hero-fineprint { display: none; }
}

/* A cut-off answer is a fact about the answer, not an error. */
.cut {
  display: flex; align-items: center; gap: 10px;
  margin-top: 12px;
  font-size: 14px;
  color: var(--ink-2);
}

.cut .act {
  color: var(--accent);
  padding: 5px 12px;
  border: 1px solid color-mix(in srgb, var(--accent) 30%, transparent);
  border-radius: 999px;
}
.cut .act:hover { background: color-mix(in srgb, var(--accent) 8%, transparent); }

/* =========================================================
   Asking back, and what to ask next
========================================================= */

.ask-back {
  margin: 0 0 14px;
  font-size: 17px;
}

.options { display: flex; flex-wrap: wrap; gap: 8px; }

.option {
  padding: 9px 16px;
  font-size: 15px;
  color: var(--ink);
  background: var(--surface);
  border-radius: 999px;
  transition: background 0.2s var(--ease);
}
.option:hover { background: color-mix(in srgb, var(--accent) 10%, var(--surface)); }

/* Follow-ups sit quietly under the answer. Plain rows, hairline between —
   deliberately not buttons, so they read as an offer, not an instruction. */
.next {
  margin-top: 18px;
  border-top: 1px solid var(--hairline);
}

.next-label {
  margin: 14px 0 0;
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-3);
  letter-spacing: 0.01em;
}

.next-q {
  display: block;
  width: 100%;
  text-align: left;
  padding: 12px 2px;
  font-size: 15.5px;
  color: var(--ink-2);
  border-bottom: 1px solid var(--hairline);
  transition: color 0.18s var(--ease), padding-left 0.18s var(--ease);
}
.next-q:last-child { border-bottom: 0; }
.next-q:hover { color: var(--accent); padding-left: 6px; }

@media (max-width: 640px) {
  .options { flex-direction: column; }
  .option { width: 100%; text-align: left; }
}

/* =========================================================
   Two-tone wordmark accent. The sidebar and bar are always present
   (see #sidebar / .bar below) — .hero vs .thread is the only thing
   that swaps between the home screen and a conversation.
========================================================= */

.lb { color: var(--accent); font-weight: 700; }

/* =========================================================
   E — Interaction polish
   Nothing new at rest; these only add life to what the user does.
========================================================= */

/* Send button invites the tap once there is something to send. */
.send:not(:disabled) {
  box-shadow: 0 2px 10px color-mix(in srgb, var(--accent) 32%, transparent);
}
.send:not(:disabled):hover { transform: scale(1.06); }
.send:not(:disabled):active { transform: scale(0.9); }

/* Thinking dots: warmer tint and a slightly more organic rhythm. */
.dots i {
  background: color-mix(in srgb, var(--accent) 55%, var(--ink-2));
}

@media (prefers-reduced-motion: reduce) {
  .send:not(:disabled):hover, .fpill:hover, .card:hover { transform: none; }
}

/* =========================================================
   Mic — voice input (Web Speech API)
   Sits inside the composer, right of the text, just before send. Hidden by default and
   revealed by JS only when the browser actually supports recognition,
   so an unsupported browser never shows a dead control.
========================================================= */

.mic {
  flex: none;
  width: 34px; height: 34px;
  display: grid; place-items: center;
  border-radius: 50%;
  color: var(--ink-2);
  transition: color 0.2s var(--ease), background 0.2s var(--ease), transform 0.15s var(--ease);
}
.mic:hover { color: var(--ink); background: var(--surface); }
.mic:active { transform: scale(0.92); }

/* Listening: the accent colour and a soft pulsing ring make the live
   state unmistakable without a separate label. */
.mic.listening {
  color: var(--accent-ink);
  background: var(--accent);
  animation: micPulse 1.6s var(--ease) infinite;
}

@keyframes micPulse {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 45%, transparent); }
  70%  { box-shadow: 0 0 0 9px color-mix(in srgb, var(--accent) 0%, transparent); }
  100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 0%, transparent); }
}

/* =========================================================
   Sidebar — New chat, pinned, history
   Fixed left on desktop, off-canvas behind a scrim on mobile. Holds the
   saved-conversation list so people can return to earlier answers.
========================================================= */

:root { --side-w: 264px; }

.sidebar {
  position: fixed; inset: 0 auto 0 0; z-index: 40;
  width: var(--side-w);
  display: flex; flex-direction: column;
  background: var(--surface);
  border-right: 1px solid var(--hairline);
  padding: 12px 10px;
  transition: transform 0.28s var(--ease);
}

.side-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 4px 6px 10px;
}
.side-mark { font-size: 17px; }
.side-mark { cursor: pointer; }
.side-close .ic-collapse { display: none; }   /* desktop shows collapse icon, mobile shows X */

.side-new {
  display: flex; align-items: center; gap: 10px;
  width: 100%;
  padding: 11px 14px;
  margin-bottom: 8px;
  font-size: 15px; font-weight: 600;
  color: var(--accent-ink);
  background: var(--accent);
  border: 1px solid transparent;
  border-radius: var(--r-md);
  transition: background 0.2s var(--ease);
}
.side-new:hover { background: color-mix(in srgb, var(--accent) 88%, black); }

.side-list {
  flex: 1;
  overflow-y: auto;
  display: flex; flex-direction: column; gap: 1px;
  padding-right: 2px;
}

.side-section {
  font-size: 12px; font-weight: 600;
  color: var(--ink-2);
  padding: 12px 10px 4px;
  letter-spacing: 0.01em;
}

.side-item {
  display: flex; align-items: center; gap: 6px;
  padding: 9px 10px;
  border-radius: var(--r-sm);
  cursor: pointer;
  transition: background 0.15s var(--ease);
}
.side-item:hover { background: color-mix(in srgb, var(--ink) 5%, transparent); }
.side-item.active { background: color-mix(in srgb, var(--accent) 12%, transparent); }

.side-item-title {
  flex: 1;
  font-size: 14px;
  color: var(--ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

.side-item-acts {
  display: flex; gap: 2px;
  position: absolute; right: 6px;
  padding-left: 14px;
  background: linear-gradient(to right,
    transparent, var(--surface) 14px, var(--surface));
  opacity: 0;
  transition: opacity 0.15s var(--ease);
}

.side-item { position: relative; }
.side-item:hover .side-item-acts { background: linear-gradient(to right,
    transparent, color-mix(in srgb, var(--ink) 5%, var(--surface)) 14px,
    color-mix(in srgb, var(--ink) 5%, var(--surface))); }
.side-item:hover .side-item-acts,
.side-item.menu-open .side-item-acts { opacity: 1; }

.side-mini {
  width: 26px; height: 26px;
  display: grid; place-items: center;
  border-radius: 6px;
  color: var(--ink-2);
}
.side-mini:hover { background: var(--canvas); color: var(--ink); }
.side-mini.is-pinned { color: var(--accent); }

.side-empty {
  padding: 16px 10px;
  font-size: 13.5px;
  color: var(--ink-2);
  line-height: 1.5;
}

.side-foot-btn {
  display: flex; align-items: center; gap: 10px;
  width: 100%;
  padding: 10px 12px;
  font-size: 14px;
  color: var(--ink-2);
  border-radius: var(--r-sm);
  transition: background 0.15s var(--ease), color 0.15s var(--ease);
}
.side-foot-btn:hover { background: color-mix(in srgb, var(--ink) 5%, transparent); color: var(--ink); }

/* Rename input reuses the row footprint. */
.side-rename {
  flex: 1;
  font-size: 14px;
  padding: 2px 6px;
  border: 1px solid var(--accent);
  border-radius: 6px;
  background: var(--canvas);
  color: var(--ink);
}
.side-rename:focus { outline: none; }

/* =========================================================
   Layout shift: main content sits right of the sidebar on desktop
========================================================= */

@media (min-width: 901px) {
  /* Shift content past the fixed sidebar with padding, NOT margin.
     .stage centres with `margin: 0 auto`; overriding margin-left kills that
     auto and pins the column left. Padding moves the box, auto still centres. */
  body { padding-left: var(--side-w); }
  .bar, .dock { left: var(--side-w); }
  .menu-btn { display: none; }          /* no hamburger when sidebar is fixed */
  .bar .wordmark { display: none; }     /* sidebar already shows the mark */
  .bar-inner { justify-content: flex-end; }

  /* Collapsed sidebar: content reclaims the space, header brings back
     the hamburger + wordmark so there is always a way to reopen it. */
  .sidebar { transition: transform 0.28s var(--ease), visibility 0s linear 0.28s; }
  body.side-hidden { padding-left: 0; }
  body.side-hidden .sidebar { transform: translateX(-100%); visibility: hidden; }
  body.side-hidden .bar, body.side-hidden .dock { left: 0; }
  body.side-hidden .menu-btn { display: grid; }
  body.side-hidden .bar .wordmark { display: inline-flex; }
  body.side-hidden .bar-inner { justify-content: space-between; }
  .side-close .ic-x { display: none; }
  .side-close .ic-collapse { display: block; }
}

/* =========================================================
   Mobile: sidebar slides in over a scrim
========================================================= */

@media (max-width: 900px) {
  .sidebar {
    transform: translateX(-100%);
    box-shadow: 0 0 40px rgba(0,0,0,0.18);
  }
  body.side-open .sidebar { transform: translateX(0); }

  .side-scrim {
    position: fixed; inset: 0; z-index: 39;
    background: rgba(0,0,0,0.32);
    animation: rise 0.2s var(--ease) both;
  }
}

@media (min-width: 901px) {
  .side-scrim { display: none !important; }
}

/* =========================================================
   "+" button, popover menu (desktop) / bottom sheet (mobile)
========================================================= */

/* Tools row inside the composer: "+" left, character counter right. */
.tools {
  flex: 0 0 100%;
  display: flex; align-items: center; gap: 8px;
  padding: 2px 4px 2px 0;
}

.plus-wrap { position: relative; }

.plus {
  flex: none;
  width: 34px; height: 34px;
  display: grid; place-items: center;
  border-radius: 50%;
  color: var(--ink-2);
  background: var(--surface);
  border: 1px solid var(--hairline);
  transition: color 0.2s var(--ease), border-color 0.2s var(--ease), transform 0.15s var(--ease);
}
.plus:hover { color: var(--ink); border-color: color-mix(in srgb, var(--accent) 40%, var(--hairline)); }
.plus:active { transform: scale(0.92); }
.plus[aria-expanded="true"] { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 45%, var(--hairline)); }

.plus:disabled { opacity: 0.4; cursor: default; }

.count { margin-left: auto; font-size: 12px; color: var(--ink-2); font-variant-numeric: tabular-nums; }
.count.over { color: #d70015; }
body.dark .count.over { color: #ff6961; }

/* "Create image" toggle — swaps the composer to the /generate-image path */
.createimg {
  flex: none;
  display: inline-flex; align-items: center; gap: 6px;
  height: 34px;
  padding: 0 12px;
  font-size: 13.5px;
  color: var(--ink-2);
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 999px;
  transition: color 0.2s var(--ease), border-color 0.2s var(--ease), background 0.2s var(--ease);
}
.createimg:hover { color: var(--ink); border-color: color-mix(in srgb, var(--accent) 40%, var(--hairline)); }
.createimg-close { display: none; }
.createimg[aria-pressed="true"] {
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 8%, var(--canvas));
  border-color: color-mix(in srgb, var(--accent) 45%, var(--hairline));
}
.createimg[aria-pressed="true"] .createimg-close { display: block; }

/* Desktop: a plain popover under the button. */
.sheet-handle, .sheet-title, .sheet-cancel { display: none; }

.plus-menu {
  position: absolute;
  bottom: calc(100% + 8px); left: 0;
  z-index: 10;
  width: 280px;
  padding: 6px;
  background: var(--canvas);
  border: 1px solid var(--hairline);
  border-radius: var(--r-md);
  box-shadow: var(--composer-shadow);
  animation: rise 0.15s var(--ease) both;
}

.plus-item {
  display: flex; align-items: center; gap: 12px;
  width: 100%;
  padding: 10px 10px;
  text-align: left;
  border-radius: 8px;
  color: var(--ink);
  transition: background 0.15s var(--ease);
}
.plus-item:hover { background: var(--surface); }
.plus-item svg { flex: none; color: var(--ink-2); }
.plus-item b { display: block; font-size: 14px; font-weight: 500; }
.plus-item small { display: block; margin-top: 1px; font-size: 12px; color: var(--ink-3); }

.sheet-scrim {
  position: fixed; inset: 0; z-index: 45;
  background: rgba(0, 0, 0, 0.4);
}
.sheet-scrim[hidden] { display: none; }

/* Mobile: the same menu becomes a bottom sheet over a scrim. */
@media (max-width: 767px) {
  .plus-menu {
    position: fixed; inset: auto 0 0 0; left: 0; right: 0; bottom: 0;
    z-index: 46;
    width: auto;
    padding: 10px 14px calc(14px + env(safe-area-inset-bottom));
    border: 0; border-top: 1px solid var(--hairline);
    border-radius: 20px 20px 0 0;
    animation: sheetUp 0.22s var(--ease) both;
  }
  .sheet-handle {
    display: block;
    width: 36px; height: 4px;
    margin: 2px auto 10px;
    border-radius: 999px;
    background: var(--hairline);
  }
  .sheet-title {
    display: block;
    margin: 0 4px 8px;
    font-size: 13px; font-weight: 600;
    color: var(--ink-3);
  }
  .plus-item { padding: 12px 10px; }
  .sheet-cancel {
    display: block;
    width: 100%;
    margin-top: 6px;
    padding: 12px;
    text-align: center;
    font-size: 15px; font-weight: 600;
    color: var(--ink);
    background: var(--surface);
    border-radius: var(--r-md);
  }
  /* Take photo first on mobile, per spec; desktop keeps source order. */
  #takePhotoBtn { order: 1; }
  #uploadPhotoBtn { order: 2; }
  #genImageBtn { order: 3; }
  .sheet-cancel { order: 4; }
  /* :not([hidden]) — a bare .plus-menu{display:flex} here would outrank
     the browser's own [hidden]{display:none} at equal specificity (author
     CSS beats the UA stylesheet), showing the sheet open on every load. */
  .plus-menu:not([hidden]) { display: flex; flex-direction: column; }
}

@keyframes sheetUp {
  from { transform: translateY(100%); }
  to   { transform: translateY(0); }
}

/* =========================================================
   Desktop "Take photo" — live camera modal (getUserMedia)
========================================================= */

.cam-modal {
  position: fixed; inset: 0; z-index: 60;
  display: flex; align-items: center; justify-content: center;
  padding: 24px;
  background: rgba(0, 0, 0, 0.6);
}
.cam-modal[hidden] { display: none; }

.cam-inner {
  position: relative;
  width: 100%;
  max-width: 560px;
  padding: 16px;
  background: var(--canvas);
  border-radius: var(--r-lg);
  box-shadow: var(--composer-shadow);
}

.cam-close {
  position: absolute;
  top: 10px; right: 10px;
  background: color-mix(in srgb, var(--canvas) 70%, transparent);
}

.cam-video {
  width: 100%;
  aspect-ratio: 4 / 3;
  border-radius: var(--r-md);
  background: #000;
  object-fit: cover;
}

.cam-error {
  margin: 14px 4px 0;
  font-size: 14px;
  color: var(--ink-2);
  text-align: center;
}

.cam-controls {
  display: flex; align-items: center; justify-content: space-between;
  margin-top: 14px;
}

.cam-choose {
  font-size: 13.5px;
  color: var(--accent);
}
.cam-choose:hover { text-decoration: underline; }

.cam-spacer { width: 80px; }

.cam-capture {
  width: 60px; height: 60px;
  flex: none;
  border-radius: 50%;
  background: var(--canvas);
  border: 3px solid var(--ink);
  transition: transform 0.15s var(--ease);
}
.cam-capture:active { transform: scale(0.92); }

.tip {
  position: absolute; bottom: calc(100% + 8px); z-index: 5;
  padding: 6px 10px;
  font-size: 12.5px; white-space: nowrap;
  color: var(--canvas); background: var(--ink);
  border-radius: 8px;
  animation: rise 0.2s var(--ease) both;
}

/* Recording: the composer itself pulses red, so it reads even off-screen. */
.composer.listening { border-color: #d70015; animation: recPulse 1.4s var(--ease) infinite; }
@keyframes recPulse {
  0%   { box-shadow: 0 0 0 0 rgba(215, 0, 21, 0.35); }
  70%  { box-shadow: 0 0 0 8px rgba(215, 0, 21, 0); }
  100% { box-shadow: 0 0 0 0 rgba(215, 0, 21, 0); }
}

/* Staged image sits just above the composer until the question is sent. */
.img-chip {
  position: relative;
  display: inline-block;
  margin: 0 auto 8px;
  flex: none;
}
.img-chip img {
  display: block;
  width: 64px; height: 64px;
  object-fit: cover;
  border-radius: var(--r-md);
  border: 1px solid var(--hairline);
}
.img-chip-x {
  position: absolute;
  top: -6px; right: -6px;
  flex: none;
  width: 22px; height: 22px;
  display: grid; place-items: center;
  border-radius: 50%;
  font-size: 15px; line-height: 1;
  color: #ffffff;
  background: #000000;
  border: 2px solid var(--canvas);
}
.img-chip-x:hover { background: #27272a; }

/* A generated image, as the answer to a "Create image" question. */
.turn.bot .made-image {
  display: block;
  width: 100%;
  max-width: 512px;
  height: auto;
  border-radius: var(--r-md);
  border: 1px solid var(--hairline);
  background: var(--surface);
}
.acts a.act { text-decoration: none; }

/* An attached image shown in the user's own turn. */
.turn.you .you-image {
  display: block;
  max-width: min(260px, 70%);
  max-height: 260px;
  margin: 0 0 8px auto;         /* right-aligned, like the user bubble */
  border-radius: 14px;
  border: 1px solid var(--hairline);
  object-fit: cover;
}
/* =========================================================
   Sidebar — "Generate image" entry (distinct accent)
========================================================= */

.side-foot-btn--accent {
  color: var(--accent-image);
}
.side-foot-btn--accent:hover {
  background: color-mix(in srgb, var(--accent-image) 12%, transparent);
  color: var(--accent-image);
}
.side-foot-btn--accent svg { stroke: var(--accent-image); }

.side-imagegen {
  display: flex; align-items: center; gap: 10px;
  width: 100%;
  padding: 11px 14px;
  margin-bottom: 18px;
  font-size: 15px; font-weight: 500;
  color: var(--accent-image);
  background: transparent;
  border: 1px solid var(--hairline);
  border-radius: var(--r-md);
  transition: background 0.2s var(--ease), border-color 0.2s var(--ease);
}
.side-imagegen svg { stroke: var(--accent-image); }
.side-imagegen:hover {
  background: color-mix(in srgb, var(--accent-image) 8%, transparent);
  border-color: color-mix(in srgb, var(--accent-image) 35%, var(--hairline));
}

/* =========================================================
   Image generation — dedicated view (not a dialog)
   A sibling of .hero and .thread inside <main>. body.imggen-active hides
   the other two and the composer dock, and shows this instead — same
   pattern as the existing hero<->thread swap, one class further.
========================================================= */

.imggen { display: none; }

/* Decisive, independent of the imggen-active class below: whatever state
   that class ends up in, the hidden attribute (toggled in lockstep with it
   in app.js) always wins. Belt-and-suspenders — same proven pattern as
   #dock's own [hidden] toggle elsewhere on this page. */
.imggen[hidden] { display: none !important; }

body.imggen-active .hero,
body.imggen-active .thread,
body.imggen-active .dock { display: none !important; }

/* .stage caps at --col (692px) for chat's reading width. This view isn't
   reading prose, so let it use the full width the .imggen-inner clamp
   below actually allows — otherwise the parent silently overrides every
   width decision made here, which is exactly what happened before this
   rule existed: .imggen-inner grew, but .stage never let it show. */
body.imggen-active .stage {
  max-width: none;
  padding-left: 0;
  padding-right: 0;
}

body.imggen-active .imggen {
  display: flex;
  flex-direction: column;
  min-height: calc(100vh - var(--bar-h));
  margin-top: var(--bar-h);
}

/* Wider than --col (692px) on purpose — this view's job is showing a
   generated image at a useful size, not reading prose, so it earns more
   room. Scales with the viewport instead of a fixed ceiling: chat is
   capped because long lines of prose get hard to read past a width;
   there's no equivalent reason to cap a canvas that could use the space
   a wide screen actually has. 1400px keeps it from going absurd on an
   ultrawide monitor; clamp's lower bound is a no-op below that width,
   since width:100% already shrinks it on narrow viewports. */
.imggen-inner {
  width: 100%;
  max-width: clamp(880px, 92vw, 1400px);
  margin: 0 auto;
  padding: 24px 24px 40px;
}

.imggen-bar {
  display: flex; align-items: center; gap: 10px;
  margin-bottom: 20px;
}

.imggen-back {
  width: 30px; height: 30px;
  display: grid; place-items: center;
  border-radius: 50%;
  color: var(--ink-2);
}
.imggen-back:hover { background: color-mix(in srgb, var(--ink) 6%, transparent); color: var(--ink); }

.imggen-title {
  font-size: 16px; font-weight: 500;
  color: var(--accent-image);
}

.imggen-body {
  display: grid;
  grid-template-columns: 280px minmax(0, 1fr);
  gap: 40px;
}

.imggen-controls {
  display: flex; flex-direction: column; gap: 12px;
  align-content: start;
}

.imggen-prompt-wrap { position: relative; }

#imgPrompt {
  width: 100%;
  resize: vertical;
  min-height: 90px;
  padding: 12px 44px 12px 14px;
  font: inherit;
  font-size: 15px;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: var(--r-md);
  transition: border-color 0.2s var(--ease);
}
#imgPrompt:focus-visible {
  outline: none;
  border-color: color-mix(in srgb, var(--accent-image) 55%, var(--hairline));
}

.imgmic {
  position: absolute;
  top: 8px; right: 8px;
  width: 30px; height: 30px;
  display: grid; place-items: center;
  border-radius: 50%;
  color: var(--ink-2);
  transition: color 0.2s var(--ease), background 0.2s var(--ease), transform 0.15s var(--ease);
}
.imgmic:hover { color: var(--ink); background: var(--canvas); }
.imgmic:active { transform: scale(0.92); }

.imgmic.listening {
  color: var(--accent-image-ink);
  background: var(--accent-image);
  animation: imgmicPulse 1.6s var(--ease) infinite;
}

@keyframes imgmicPulse {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent-image) 45%, transparent); }
  70%  { box-shadow: 0 0 0 9px color-mix(in srgb, var(--accent-image) 0%, transparent); }
  100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent-image) 0%, transparent); }
}

#imgModel {
  width: 100%;
  padding: 10px 12px;
  font: inherit;
  font-size: 14px;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: var(--r-sm);
}

.imggen-generate {
  width: 100%;
  padding: 10px;
  font-size: 14px; font-weight: 600;
  color: var(--accent-image-ink);
  background: var(--accent-image);
  border-radius: var(--r-sm);
  transition: opacity 0.2s var(--ease), transform 0.1s var(--ease);
}
.imggen-generate:hover { opacity: 0.9; }
.imggen-generate:active { transform: scale(0.97); }
.imggen-generate:disabled { opacity: 0.5; cursor: default; }

.imggen-history-label {
  font-size: 12px;
  color: var(--ink-2);
  margin: 0 0 8px;
}

.imggen-history-row {
  display: flex; gap: 8px;
  flex-wrap: wrap;
}

.imggen-thumb {
  width: 48px; height: 48px;
  flex: none;
  border-radius: 8px;
  border: 2px solid transparent;
  background-size: cover;
  background-position: center;
  transition: border-color 0.2s var(--ease);
}
.imggen-thumb.active { border-color: var(--accent-image); }
.imggen-thumb:hover { border-color: color-mix(in srgb, var(--accent-image) 50%, var(--hairline)); }

.imggen-canvas {
  display: flex; flex-direction: column; align-items: center; justify-content: flex-start;
  gap: 14px;
}

.imggen-frame {
  width: 100%;
  max-width: min(720px, 100%);
  max-height: 65vh;
  aspect-ratio: 1;
  border-radius: var(--r-lg);
  background: var(--surface);
  border: 1px solid var(--hairline);
  display: flex; align-items: center; justify-content: center;
  overflow: hidden;
}

.imggen-placeholder { color: var(--ink-2); }
.imggen-placeholder svg { stroke: var(--ink-2); }

.imggen-frame img {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
}

.imggen-frame.loading .imggen-placeholder {
  animation: imggenPulse 1.4s infinite ease-in-out;
}

@keyframes imggenPulse {
  0%, 100% { opacity: 0.35; }
  50% { opacity: 0.8; }
}

.imggen-error {
  max-width: 480px;
  width: 100%;
  padding: 12px 16px;
  font-size: 14px;
  color: #d92c2c;
  background: color-mix(in srgb, #d92c2c 8%, transparent);
  border-radius: var(--r-md);
  text-align: center;
}

.imggen-actions {
  display: flex; gap: 8px;
}

.imggen-action {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 9px 16px;
  font-size: 14px; font-weight: 500;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: var(--r-sm);
  transition: border-color 0.2s var(--ease);
}
.imggen-action svg { stroke: currentColor; }
.imggen-action:hover { border-color: color-mix(in srgb, var(--accent-image) 40%, var(--hairline)); }

/* Tablet: controls become a row above the canvas instead of a sidebar. */
@media (max-width: 900px) {
  .imggen-body {
    grid-template-columns: 1fr;
  }
  .imggen-controls {
    padding-bottom: 16px;
    margin-bottom: 16px;
    border-bottom: 1px solid var(--hairline);
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
  }
  .imggen-prompt-wrap { flex: 1 1 100%; }
  #imgModel { flex: 1; width: auto; }
  .imggen-generate { width: auto; padding: 10px 20px; }
  .imggen-history { flex: 1 1 100%; }
}

/* Mobile: fully stacked, single column. */
@media (max-width: 640px) {
  .imggen-inner { padding: 20px 16px 32px; }
  .imggen-controls {
    flex-direction: column;
  }
  #imgModel { width: 100%; }
  .imggen-generate { width: 100%; }
}

/* =========================================================
   Mobile — 44px touch targets on the primary controls. Desktop keeps
   its smaller mouse-driven sizes; this is scoped to touch widths only.

   Not bumped here, flagged rather than silently changed or skipped:
   the dense secondary rows — .acts (Copy/Regenerate), .next-q
   (follow-ups), .option (clarify choices), the sidebar's hover-reveal
   delete ×, and the image generator's Regenerate/Download buttons.
   A blind 44px minimum on those would visibly break their current
   compact, text-link layout, so this needs its own pass if you want it.
========================================================= */

@media (max-width: 640px) {
  .ghost, .mic, .send, .plus, .imgmic, .imggen-back {
    width: 44px; height: 44px;
  }
  .chip, .createimg { height: 44px; }
  .side-new, .side-imagegen, .cam-choose { min-height: 44px; }
}