/* ==========================================================================
   NOX chat v2 — bold crimson rebrand of the conversation screen.

   Replaces these chat-page-only stylesheets (verified: no other page links them):
     chat.css, nox-chat.css, chat-parity.css, chat-workspace.css,
     chat-stage-interactive.css, conversation-media.css

   Shared sheets deliberately NOT touched:
     fonts.css, story-palettes.css, conversation-setup.css, story-share.css,
     vendor/lucide/lucide.css

   Single accent: brand crimson #f0323f (docs/wordmark-red-20260905.md).
   ========================================================================== */

/* Compact scene cards, matching the reference's two tiles, notes and inner monologue. */
.nox-scene-notebook {
  width: 100%; min-width: 0; margin-top: 10px;
  border: 1px solid #27272a; border-radius: 12px;
  background: #09090b; color: #f4f4f5;
  box-shadow: 0 4px 12px #0004; overflow: hidden;
  font-family: var(--nox-font-sans); font-size: 14px; line-height: 1.55; overflow-wrap: anywhere;
}
.notebook-summary { position: relative; display: block; min-height: 44px; padding: 14px; cursor: pointer; list-style: none; }
.notebook-summary::-webkit-details-marker { display: none; }
.notebook-summary:focus-visible { outline: 2px solid #818cf8; outline-offset: -3px; border-radius: 12px; }
.notebook-scene { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 8px; }
.notebook-scene-cell { display: grid; align-content: start; gap: 2px; min-width: 0; padding: 8px 10px; border-radius: 8px; border-left: 3px solid #3b82f6; background: #18181b; }
.notebook-scene-cell[data-field="location"] { border-left-color: #10b981; padding-right: 18px; }
.notebook-scene-cell:only-child { grid-column: 1 / -1; }
.notebook-scene-label { display: flex; align-items: center; gap: 4px; color: #a1a1aa; font-size: 11px; line-height: 16px; }
.notebook-field-icon { font-style: normal; }
.notebook-scene-value { color: #f4f4f5; font-size: 14px; font-weight: 600; line-height: 20px; }
.notebook-fallback-title { color: #a1a1aa; font-size: 13px; padding: 2px 4px; }
.notebook-fold { position: absolute; right: 20px; top: 23px; width: 6px; height: 6px; border: solid #a1a1aa; border-width: 0 1px 1px 0; transform: rotate(45deg); }
.nox-scene-notebook[open] .notebook-fold { top: 26px; transform: rotate(225deg); }
.nox-scene-notebook[open] .notebook-summary { padding-bottom: 10px; }
.notebook-content { display: grid; gap: 10px; padding: 0 14px 14px; }
.notebook-notes { display: grid; gap: 6px; margin: 0; padding: 10px; border-radius: 8px; background: #18181b; }
.notebook-notes > div { display: grid; grid-template-columns: 45px minmax(0, 1fr); align-items: center; gap: 8px; }
.notebook-notes > div + div { padding-top: 6px; border-top: 1px solid #27272a; }
.notebook-notes dt { color: #fbbf24; font-size: 12px; font-weight: 600; padding-top: 1px; }
.notebook-notes [data-field="tasks"] dt { color: #a78bfa; }
.notebook-notes dd { margin: 0; color: #e4e4e7; font-size: 13px; line-height: 1.4; }
.notebook-notes p + p { margin-top: 6px; }
.notebook-empty { color: #a1a1aa; }
.notebook-thought { margin: 0; padding: 10px; border: 1px solid #312e81; border-radius: 8px; background: linear-gradient(135deg, #1e1b4b, #09090b); }
.notebook-thought figcaption { display: flex; align-items: center; gap: 4px; color: #a5b4fc; font-size: 11px; line-height: 16px; font-weight: 600; }
.notebook-thought blockquote { margin: 4px 0 0; color: #c7d2fe; font-size: 13px; font-style: italic; line-height: 1.4; }

:root {
  --nox-crimson: #f0323f;
  --nox-crimson-hot: #ff5563;
  --nox-crimson-deep: #5a0d15;
  --nox-crimson-ink: #1a0508;
  --nox-bg: #000000;
  --nox-s1: #0d0d10;
  --nox-s2: #16161b;
  --nox-s3: #1e1e24;
  --nox-line: rgba(255, 255, 255, .08);
  --nox-line-strong: rgba(255, 255, 255, .14);
  --nox-crimson-line: rgba(240, 50, 63, .18);
  --nox-t1: #f7f6f8;
  --nox-t2: #b9b6bf;
  --nox-t3: #7c7a85;
  --nox-gold: #f3d68c;
  --nox-green: #42d68f;
  --nox-glass: rgba(8, 8, 10, .72);
  --nox-glass-strong: rgba(8, 8, 10, .90);
  --nox-r-sm: 10px;
  --nox-r-md: 14px;
  --nox-r-lg: 20px;
  --nox-r-pill: 999px;
  --nox-shadow: 0 18px 48px rgba(0, 0, 0, .55);
  --nox-glow: 0 0 26px rgba(240, 50, 63, .26);
}

/* --- reset (the only page-wide reset used to live in the retired chat.css) --- */
*, *::before, *::after { box-sizing: border-box; }
html, body { height: 100%; }
body, h1, h2, h3, p, figure { margin: 0; }
body {
  overflow: hidden;
  background: var(--nox-bg);
  color: var(--nox-t1);
  font-family: var(--nox-font-sans);
  -webkit-font-smoothing: antialiased;
}
button, input, textarea, select { font: inherit; color: inherit; }
button { -webkit-tap-highlight-color: transparent; cursor: pointer; }
/* One global rule honours the whole hidden-attribute contract, so no per-selector
   !important patch is needed the way the retired sheets required. */
[hidden] { display: none !important; }
:focus-visible { outline: 2px solid var(--nox-crimson-hot); outline-offset: 2px; }

/* ==========================================================================
   Workspace shell
   ========================================================================== */

.nox-chat-workspace { display: block; height: 100dvh; }

.chat-container {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100dvh;
  min-height: 0;
  overflow: hidden;
  background:
    radial-gradient(90% 55% at 18% 8%, rgba(240, 50, 63, .10), transparent 62%),
    var(--nox-s1);
}

/* --- icon rail: hidden on mobile, the left spine on desktop --- */
.nox-icon-rail { display: none; }
.nox-login-rail { display: none; }

/* ==========================================================================
   Topbar
   ========================================================================== */

.chat-topbar {
  position: relative;
  z-index: 20;
  flex: none;
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 68px;
  padding: calc(10px + env(safe-area-inset-top)) 14px 10px;
  border-bottom: 1px solid var(--nox-line);
  background: var(--nox-glass-strong);
  backdrop-filter: blur(20px) saturate(1.2);
  -webkit-backdrop-filter: blur(20px) saturate(1.2);
}

.topbar-btn,
.chat-topbar .icon-button {
  display: grid;
  place-items: center;
  flex: none;
  width: 38px;
  height: 38px;
  padding: 0;
  border: 0;
  border-radius: var(--nox-r-pill);
  background: transparent;
  color: var(--nox-t2);
  text-decoration: none;
  transition: background .18s ease, color .18s ease, transform .15s ease;
}
.topbar-btn:hover,
.chat-topbar .icon-button:hover { background: rgba(255, 255, 255, .08); color: #fff; }
.topbar-btn:active { transform: scale(.92); }
.topbar-btn > i, .chat-topbar .icon-button > i { font-size: 20px; line-height: 1; }

.topbar-avatar {
  position: relative;
  flex: none;
  width: 42px;
  height: 42px;
  border-radius: var(--nox-r-pill);
  background: var(--nox-s3);
  box-shadow: 0 0 0 1px rgba(255, 255, 255, .12), 0 0 0 3px rgba(240, 50, 63, .10);
}
.topbar-avatar img {
  display: block;
  width: 100%;
  height: 100%;
  border-radius: inherit;
  object-fit: cover;
  object-position: center 18%;
}
.topbar-avatar > i {
  position: absolute;
  right: -1px;
  bottom: 0;
  width: 11px;
  height: 11px;
  border: 2px solid var(--nox-s1);
  border-radius: var(--nox-r-pill);
  background: var(--nox-green);
  box-shadow: 0 0 7px rgba(66, 214, 143, .7);
}

.topbar-title {
  display: flex;
  flex: 1;
  min-width: 0;
  flex-direction: column;
  align-items: flex-start;
  gap: 3px;
  text-align: left;
}
.topbar-name { display: flex; align-items: baseline; gap: 6px; min-width: 0; line-height: 1; }
.topbar-name b {
  overflow: hidden;
  color: #fff;
  font-size: 17px;
  font-weight: 850;
  letter-spacing: -.02em;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.topbar-name em { color: var(--nox-gold); font-size: 11px; font-style: normal; font-weight: 750; }
.topbar-name em::after { content: '세'; }
.topbar-status {
  display: flex;
  align-items: center;
  gap: 5px;
  min-width: 0;
  color: var(--nox-t3);
  font-size: 12.5px;
}
.topbar-status > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.status-dot {
  flex: none;
  width: 6px;
  height: 6px;
  border-radius: var(--nox-r-pill);
  background: var(--nox-green);
  animation: dot-pulse 2s ease-in-out infinite;
}
@keyframes dot-pulse { 50% { opacity: .35; } }

.nox-credit-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  flex: none;
  min-width: 60px;
  height: 34px;
  padding: 0 11px;
  border: 1px solid var(--nox-crimson-line);
  border-radius: var(--nox-r-pill);
  background: rgba(240, 50, 63, .12);
  color: var(--nox-gold);
  font-size: 12px;
  font-weight: 850;
  transition: border-color .18s ease, background .18s ease;
}
.nox-credit-btn i { font-size: 12px; }
.nox-credit-btn:hover { border-color: rgba(240, 50, 63, .55); background: rgba(240, 50, 63, .22); }

/* ==========================================================================
   Character stage
   ========================================================================== */

/* The stage and the transcript share the column through --chat-stage-size: the stage
   holds its basis but is allowed to shrink, while the transcript refuses to shrink
   below its own basis. That is what keeps the conversation visible when the gate card
   or an attachment composer appears, instead of the portrait eating the viewport. */
#chatRoot .chat-context {
  --chat-stage-size: min(34dvh, 300px);
  /* A size container so the overlay can answer to the stage's real height rather than the
     viewport's. The stage shrinks by flex, not by media query, so only this can tell the
     overlay how much room it actually has. */
  container-type: size;
  container-name: stage;
  position: relative;
  isolation: isolate;
  flex: 0 1 var(--chat-stage-size);
  height: var(--chat-stage-size);
  min-height: 58px;
  overflow: hidden;
  border-bottom: 1px solid var(--nox-line);
  background: var(--nox-s2);
  transition: height .2s ease, flex-basis .2s ease;
}
#chatRoot .chat-context.is-compact { --chat-stage-size: clamp(88px, 12dvh, 112px); }
/* Ambient wash built from the same image chat.js publishes as --character-preview.
   Split longhands, not the shorthand: an unset custom property makes a shorthand
   invalid at computed-value time and the whole declaration is dropped. */
.chat-context::before {
  content: '';
  position: absolute;
  z-index: -3;
  inset: -30%;
  background-image: var(--character-preview);
  background-position: center;
  background-size: cover;
  background-repeat: no-repeat;
  filter: blur(46px) saturate(1.2);
  opacity: .34;
}

.nox-chat-character {
  position: absolute;
  z-index: -2;
  top: -30%;
  right: 0;
  width: 72%;
  height: 165%;
  object-fit: cover;
  object-position: center top;
  opacity: .95;
  filter: saturate(.95) contrast(1.04) brightness(.92);
}
/* Wide banner crop ignores the portrait framing and fills the whole stage frame. */
#chatRoot .nox-chat-character.is-wide { top: 0; right: 0; width: 100%; height: 100%; object-fit: cover; object-position: 62% 30%; opacity: 1; }

/* Collapsed stage: a 108px thumbnail docked right, caption moved up beside it. */
#chatRoot .chat-context.is-compact .nox-chat-character { top: 0; right: 0; width: 108px; height: 100%; object-position: center 22%; }
#chatRoot .chat-context.is-compact .nox-chat-character.is-wide { width: 100%; object-position: 68% 22%; }
#chatRoot .chat-context.is-compact:has(.nox-chat-character.is-wide) .nox-story-caption { right: 16px; }
#chatRoot .chat-context.is-compact .nox-story-caption { left: 15px; right: 124px; top: 16px; bottom: auto; gap: 4px; }
#chatRoot .chat-context.is-compact .nox-story-caption span { font-size: 10px; }
#chatRoot .chat-context.is-compact .nox-story-caption strong {
  display: -webkit-box;
  overflow: hidden;
  font-size: 14px;
  line-height: 1.45;
  white-space: normal;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
}
#chatRoot .chat-context.is-compact .nox-character-stage-toggle { top: auto; right: 7px; bottom: 7px; }

.nox-chat-gradient {
  position: absolute;
  z-index: -1;
  inset: 0;
  background:
    linear-gradient(90deg, var(--nox-s1) 0%, rgba(13, 13, 16, .94) 30%, rgba(13, 13, 16, .42) 62%, rgba(0, 0, 0, .06) 100%),
    linear-gradient(0deg, rgba(0, 0, 0, .95) 0%, rgba(0, 0, 0, .38) 44%, transparent 78%);
}

.nox-story-caption { position: absolute; left: 20px; right: 34%; bottom: 24px; display: grid; gap: 6px; }
.nox-story-caption span {
  overflow: hidden;
  color: var(--nox-t2);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .01em;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* The hook is the character's opening line, a full sentence - not a display title. As a
   clamped 2-line quote it teases; at 32px across three lines it buried the portrait and
   was truncated mid-word once the 390px stage narrowed it. */
.nox-story-caption strong {
  display: -webkit-box;
  overflow: hidden;
  color: #fff;
  font-size: clamp(16px, 4.3vw, 22px);
  font-weight: 780;
  line-height: 1.38;
  letter-spacing: -.028em;
  text-shadow: 0 2px 16px rgba(0, 0, 0, .85);
  white-space: normal;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
}

/* chat.js:1251 sets .nox-relation hidden on every load and never restores it, so this
   node is never visible. The rules survive only so the selector isn't dangling. */
.nox-relation { position: absolute; left: 20px; right: 20px; bottom: 24px; display: grid; grid-template-columns: auto 1fr; align-items: center; gap: 11px; }
.nox-relation > span { color: var(--nox-t3); font-size: 11px; font-weight: 750; white-space: nowrap; }
.nox-relation b { color: #f6c3c8; }
.nox-relation > i { height: 4px; overflow: hidden; border-radius: var(--nox-r-pill); background: rgba(255, 255, 255, .12); }
.nox-relation em { display: block; height: 100%; border-radius: inherit; background: linear-gradient(90deg, var(--nox-crimson-deep), var(--nox-crimson)); box-shadow: var(--nox-glow); transition: width .45s ease; }

.nox-character-stage-toggle {
  position: absolute;
  z-index: 6;
  right: 14px;
  top: 12px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 12px;
  border: 1px solid var(--nox-line-strong);
  border-radius: var(--nox-r-pill);
  background: rgba(0, 0, 0, .58);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  color: #fff;
  font-size: 12px;
  font-weight: 700;
}
.nox-character-stage-toggle:hover { border-color: var(--nox-crimson-line); background: rgba(240, 50, 63, .18); }

/* stage gallery controls + transient feedback (created by chat-stage-interactive.js).
   Markup is [prev][counter][next]. Navigation and orientation are split apart: the arrows
   go to the vertical middle of each edge, where they read as left/right, and the counter
   becomes a small chip at top centre. As one 133px pill in the top-left it sat directly
   under the back button and consumed a third of a 390px stage. */
.stage-gallery-controls {
  position: absolute;
  z-index: 5;
  inset: 0;
  pointer-events: none;
}
.stage-gallery-controls button {
  position: absolute;
  top: 50%;
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  padding: 0;
  border: 1px solid rgba(255, 255, 255, .16);
  border-radius: 50%;
  background: rgba(12, 12, 15, .58);
  color: #fff;
  font-size: 19px;
  cursor: pointer;
  pointer-events: auto;
  transform: translateY(-50%);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  transition: background .16s ease, border-color .16s ease;
}
.stage-gallery-controls button:first-of-type { left: 12px; }
.stage-gallery-controls button:last-of-type { right: 12px; }
.stage-gallery-controls button:hover { border-color: var(--nox-crimson-line); background: rgba(240, 50, 63, .5); }
.stage-gallery-controls span {
  position: absolute;
  top: 12px;
  left: 50%;
  padding: 4px 10px;
  border: 1px solid rgba(255, 255, 255, .12);
  border-radius: var(--nox-r-pill);
  background: rgba(12, 12, 15, .58);
  color: #e9e7ed;
  font-size: 11px;
  font-weight: 700;
  white-space: nowrap;
  transform: translateX(-50%);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
.stage-feedback {
  position: absolute;
  z-index: 5;
  right: 14px;
  top: 58px;
  max-width: 70%;
  padding: 7px 11px;
  border: 1px solid var(--nox-line-strong);
  border-radius: var(--nox-r-lg);
  background: rgba(0, 0, 0, .7);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  color: var(--nox-t1);
  font-size: 11.5px;
  pointer-events: none;
}
#characterHero[data-reply-state="waiting"] .stage-feedback { border-color: rgba(251, 83, 106, .6); color: #ffbac4; }
#characterHero[data-reply-state="received"] .stage-feedback { border-color: var(--nox-crimson-hot); color: #fff; }
#characterHero .nox-chat-gradient,
#characterHero .nox-story-caption { pointer-events: none; }
#characterImage { touch-action: pan-y; cursor: grab; }
#characterImage:active { cursor: grabbing; }
/* A collapsed stage is a 108px strip with no room for mid-edge arrows or a counter chip
   without covering the caption. Gallery navigation stays available there as a swipe on the
   thumbnail and as ArrowLeft/ArrowRight on it (chat-stage-interactive.js:39-41). */
#characterHero.is-compact .stage-gallery-controls { display: none; }
#characterHero.is-compact .stage-feedback { top: auto; bottom: 10px; right: 10px; font-size: 11px; }
#characterHero.is-compact .nox-story-caption {
  left: 15px;
  right: 124px;
  top: 16px;
  bottom: auto;
}
#characterHero.is-compact .nox-story-caption strong { font-size: 15px; }

/* ==========================================================================
   Conversation-context button
   ========================================================================== */

.nox-conversation-context {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  margin: 0;
  padding: 13px 18px;
  border: 0;
  border-bottom: 1px solid var(--nox-line);
  background: transparent;
  color: var(--nox-t1);
  text-align: left;
  cursor: pointer;
  transition: background .18s ease;
}
.nox-conversation-context:hover { background: rgba(240, 50, 63, .07); }
.nox-conversation-context > i { flex: none; color: var(--nox-crimson); font-size: 17px; }
.nox-conversation-context > i:last-child { color: var(--nox-t3); font-size: 15px; }
.nox-conversation-context > span { flex: 1; display: grid; gap: 3px; min-width: 0; }
.nox-conversation-context strong { overflow: hidden; font-size: 14px; font-weight: 780; text-overflow: ellipsis; white-space: nowrap; }
.nox-conversation-context small { overflow: hidden; color: var(--nox-t3); font-size: 12px; text-overflow: ellipsis; white-space: nowrap; }

/* ==========================================================================
   Login gate — card banner (replaces the flat full-width strip)
   ========================================================================== */

.nox-ai-availability {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: start;
  gap: 14px;
  margin: 14px 18px 4px;
  padding: 16px 18px;
  border: 1px solid var(--nox-crimson-line);
  border-radius: var(--nox-r-lg);
  background:
    linear-gradient(135deg, rgba(240, 50, 63, .14), rgba(240, 50, 63, .04) 55%, transparent),
    var(--nox-s2);
  box-shadow: 0 12px 34px rgba(0, 0, 0, .38), inset 0 1px 0 rgba(255, 255, 255, .05);
}
.nox-ai-icon {
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  border-radius: var(--nox-r-pill);
  background: linear-gradient(135deg, var(--nox-crimson), var(--nox-crimson-deep));
  color: #fff;
  font-size: 18px;
  box-shadow: var(--nox-glow);
}
.nox-ai-copy { display: grid; gap: 5px; min-width: 0; }
.nox-ai-copy strong { color: #fff; font-size: 17px; font-weight: 800; letter-spacing: -.025em; line-height: 1.35; }
.nox-ai-copy span { color: var(--nox-t2); font-size: 13.5px; line-height: 1.6; }
.nox-ai-actions { grid-column: 2; display: flex; flex-wrap: wrap; gap: 8px; margin-top: 4px; }
.nox-ai-actions button,
#chatSignIn,
#retryAiConnection {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 42px;
  padding: 0 18px;
  border: 1px solid var(--nox-line-strong);
  border-radius: var(--nox-r-pill);
  background: rgba(255, 255, 255, .06);
  color: var(--nox-t1);
  font-size: 13.5px;
  font-weight: 750;
  white-space: nowrap;
  transition: background .18s ease, border-color .18s ease, transform .14s ease;
}
.nox-ai-actions button:active { transform: scale(.97); }
.nox-ai-actions button:hover { background: rgba(255, 255, 255, .12); }
#chatSignIn {
  border-color: transparent;
  background: linear-gradient(135deg, var(--nox-crimson), #a5182a);
  color: #fff;
  box-shadow: 0 8px 22px rgba(240, 50, 63, .32);
}
#chatSignIn:hover { background: linear-gradient(135deg, var(--nox-crimson-hot), var(--nox-crimson)); }

/* ==========================================================================
   Transcript
   ========================================================================== */

/* Transcript keeps a floor of its own. The stage above it may collapse, but the
   conversation never shrinks past this budget — the free opening scene has to stay
   readable when the composer grows an attachment row. */
.chat-messages {
  display: flex;
  flex: 1 0 clamp(100px, 24dvh, 200px);
  min-height: clamp(100px, 24dvh, 200px);
  flex-direction: column;
  gap: 16px;
  overflow-y: auto;
  padding: 18px 18px 24px;
  overscroll-behavior: contain;
  scrollbar-color: #3d3b43 transparent;
  scrollbar-width: thin;
}
.chat-messages::-webkit-scrollbar { width: 6px; }
.chat-messages::-webkit-scrollbar-thumb { border-radius: var(--nox-r-pill); background: #3d3b43; }

.msg { display: flex; align-items: flex-start; gap: 10px; width: 100%; animation: msg-in .26s ease both; }
@keyframes msg-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
.msg-bot { justify-content: flex-start; }
.msg-user { justify-content: flex-end; }

.msg-avatar {
  flex: none;
  width: 32px;
  height: 32px;
  margin: 0 0 2px;
  overflow: hidden;
  border-radius: var(--nox-r-pill);
  background: var(--nox-s3);
  box-shadow: 0 0 0 1px rgba(255, 255, 255, .1);
}
.msg-avatar img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: center 18%; }

.msg-body { display: flex; max-width: min(78%, 460px); flex-direction: column; align-items: flex-start; gap: 5px; }
.msg-user .msg-body { align-items: flex-end; }
.msg-author { padding-left: 2px; color: var(--nox-t3); font-size: 11.5px; font-weight: 700; }

.bubble {
  padding: 12px 15px;
  border-radius: 18px;
  /* All four longhands stated: the retired sheets set different corners in
     different files, which left the bot bubble squared on two opposite corners. */
  border-top-left-radius: 18px;
  border-top-right-radius: 18px;
  border-bottom-left-radius: 18px;
  border-bottom-right-radius: 18px;
  color: var(--nox-t1);
  font-size: 15px;
  line-height: 1.65;
  word-break: keep-all;
  overflow-wrap: anywhere;
  white-space: pre-wrap;
}
.msg-bot .bubble {
  border-top-left-radius: 6px;
  border-bottom-left-radius: 6px;
  border: 1px solid var(--nox-line);
  background: var(--nox-s2);
  color: var(--nox-t1);
  box-shadow: 0 4px 16px rgba(0, 0, 0, .22);
}
.msg-user .bubble {
  border-top-right-radius: 6px;
  border-bottom-right-radius: 6px;
  background: #27272a;
  color: #f5d76e;
  box-shadow: none;
}
.msg-time { padding: 0 3px; color: #5f5c65; font-size: 11px; }

.typing-dots { display: inline-flex; gap: 5px; padding: 3px 2px; }
.typing-dots span { width: 6px; height: 6px; border-radius: var(--nox-r-pill); background: var(--nox-t3); animation: dot-bounce 1.2s infinite; }
.typing-dots span:nth-child(2) { animation-delay: .15s; }
.typing-dots span:nth-child(3) { animation-delay: .3s; }
@keyframes dot-bounce { 0%, 60%, 100% { transform: none; opacity: .35; } 30% { transform: translateY(-5px); opacity: 1; } }

/* narration (novel) mode renders as prose paragraphs, not bubbles */
body.nox-narration-novel .msg-bot .bubble {
  padding: 0;
  border: 0;
  background: transparent;
  box-shadow: none;
  color: #d4d4d8;
  font-style: italic;
  font-size: 17px;
  line-height: 1.9;
}
.reply-dialogue { color: #f5d76e; font-style: normal; }
body.nox-narration-novel .msg-bot .msg-body { max-width: 100%; width: 100%; }
body.nox-narration-novel .msg-bot .msg-avatar,
body.nox-narration-novel .msg-bot .msg-author,
body.nox-narration-novel .msg-bot .msg-time { display: none; }

/* --- media inside a turn --- */
.nox-message-media { display: grid; gap: 6px; max-width: min(78vw, 320px); }
.nox-message-media img,
.nox-message-media audio { display: block; width: 100%; border-radius: var(--nox-r-md); }
.nox-message-media img { max-height: 340px; object-fit: cover; background: var(--nox-s1); }
.nox-message-media small { color: var(--nox-t3); font-size: 11px; line-height: 1.5; }
.nox-message-media button {
  min-height: 40px;
  padding: 0 14px;
  border: 1px solid var(--nox-line-strong);
  border-radius: var(--nox-r-md);
  background: rgba(255, 255, 255, .06);
  color: var(--nox-t1);
  font-size: 13px;
  font-weight: 700;
}
.nox-message-media button:hover { background: rgba(255, 255, 255, .12); }
/* Every inline image is a button, so the picture is never a fold: it is on screen
   at its natural ratio and one click opens the full-screen viewer. Only the retry
   button keeps the shared media-button chrome. */
.nox-message-media .nox-media-open {
  display: block;
  width: 100%;
  max-width: 100%;
  min-height: 0;
  padding: 0;
  border: 0;
  border-radius: var(--nox-r-md);
  background: none;
  cursor: zoom-in;
}
.nox-message-media .nox-media-open:hover { background: none; }
/* The picture sits in the transcript at its natural ratio, uncropped and uncapped:
   max-height and object-fit undo the shared .nox-message-media img thumbnail rules,
   so the inline image and the full-screen viewer show the same composition. */
.nox-message-media .nox-media-open img { display: block; width: 100%; height: auto; max-height: none; object-fit: contain; }
.nox-media-status { color: var(--nox-t3); font-size: 11px; line-height: 1.5; }

.nox-speech-button {
  min-height: 36px; padding: 6px 8px;
  border: 0; border-radius: 8px;
  background: transparent; color: #a1a1aa;
  font-size: 12px; font-weight: 400;
  transition: background .18s ease;
}
.nox-speech-button:hover { background: #ffffff0d; color: #e4e4e7; }
.nox-speech-button:disabled { opacity: .5; }

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

.chat-composer {
  position: relative;
  z-index: 10;
  flex: none;
  max-height: 45%;
  overflow-y: auto;
  scrollbar-width: thin;
  border-top: 1px solid var(--nox-line);
  background: var(--nox-glass-strong);
  backdrop-filter: blur(20px) saturate(1.2);
  -webkit-backdrop-filter: blur(20px) saturate(1.2);
}

.quick-replies {
  display: flex; flex-wrap: nowrap; gap: 8px; overflow-x: auto;
  padding: 12px 14px 2px; scrollbar-width: none;
  min-width: 0; max-width: 100%;
  overscroll-behavior-x: contain;
  touch-action: pan-x pan-y;
  -webkit-overflow-scrolling: touch;
}
.quick-replies::-webkit-scrollbar { display: none; }
.quick-replies:empty { display: none; }
/* Mouse-only drag affordance; touch keeps native pan-x/pan-y scrolling untouched. */
@media (hover: hover) and (pointer: fine) {
  .quick-replies { cursor: grab; }
  .quick-replies.is-dragging, .quick-replies.is-dragging .chip { cursor: grabbing; }
}
.quick-replies.is-dragging, .quick-replies.is-dragging .chip { user-select: none; -webkit-user-select: none; }
.quick-replies.is-dragging .chip { transition: none; }
.quick-replies.is-dragging .chip:active { transform: none; }
.chip {
  flex: none;
  white-space: nowrap;
  padding: 8px 14px;
  border: 1px solid var(--nox-crimson-line);
  border-radius: var(--nox-r-pill);
  background: rgba(240, 50, 63, .10);
  color: #ecb4b9;
  font-size: 12.5px;
  font-weight: 700;
  transition: border-color .16s ease, background .16s ease, transform .14s ease;
}
.chip:hover { border-color: rgba(240, 50, 63, .5); background: rgba(240, 50, 63, .2); }
.chip:active { transform: scale(.96); }

.nox-attachment-draft {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
  margin: 10px 14px 2px;
  padding: 12px;
  border: 1px solid var(--nox-crimson-line);
  border-radius: var(--nox-r-md);
  background: var(--nox-s2);
}
.nox-attachment-draft > img { flex: 0 0 auto; width: 62px; height: 62px; border-radius: var(--nox-r-sm); object-fit: cover; }
.nox-attachment-copy { flex: 1; min-width: 0; }
.nox-attachment-copy strong { display: block; overflow: hidden; color: var(--nox-t1); font-size: 13px; text-overflow: ellipsis; white-space: nowrap; }
.nox-attachment-copy small { display: block; margin-top: 4px; color: var(--nox-t3); font-size: 12px; line-height: 1.5; }
.nox-attachment-copy audio { display: block; width: 100%; max-width: 320px; height: 34px; margin-bottom: 6px; }
.nox-attachment-draft button {
  flex: none;
  min-height: 38px;
  padding: 0 12px;
  border: 1px solid var(--nox-line-strong);
  border-radius: var(--nox-r-sm);
  background: transparent;
  color: var(--nox-t1);
  font-size: 12.5px;
}
.nox-attachment-draft button:hover { background: rgba(255, 255, 255, .1); }
.nox-attachment-draft button:disabled { opacity: .4; cursor: wait; }

.nox-recording {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 10px 14px;
  padding: 12px 14px;
  border: 1px solid var(--nox-crimson-line);
  border-radius: var(--nox-r-md);
  background: rgba(240, 50, 63, .12);
}
.nox-recording-dot { width: 8px; height: 8px; border-radius: var(--nox-r-pill); background: var(--nox-crimson-hot); animation: dot-pulse 1.4s ease-in-out infinite; }
.nox-recording strong { flex: 1; color: var(--nox-t1); font-size: 13px; }
.nox-recording button {
  min-height: 36px;
  padding: 0 12px;
  border: 1px solid var(--nox-line-strong);
  border-radius: var(--nox-r-sm);
  background: rgba(255, 255, 255, .08);
  color: #fff;
  font-size: 12.5px;
}

.nox-composer-status { padding: 8px 16px 0; color: var(--nox-t2); font-size: 12.5px; line-height: 1.5; text-align: center; }
.nox-composer-status:empty { display: none; }

/* Image-generation status (`setMediaStatus(message, 'scene')`). One ~64px row of a 40px
   framed glyph plus two lines of copy, centred and capped so it stays compact and never
   covers the composer. The moving parts are decorative and aria-hidden in the markup,
   the copy is never animated, and the card carries no percentage or countdown — only the
   server decides when the scene arrives. Scoped entirely to .nox-composer-status-scene. */
.nox-composer-status.nox-composer-status-scene { padding-top: 10px; }
.nox-scene-status {
  display: flex;
  align-items: center;
  gap: 12px;
  max-width: 360px;
  min-height: 64px;
  margin: 0 auto;
  padding: 10px 14px;
  border: 1px solid var(--nox-crimson-line);
  border-radius: var(--nox-r-md);
  background:
    radial-gradient(120% 150% at 10% 50%, rgba(240, 50, 63, .10), transparent 62%),
    radial-gradient(120% 150% at 90% 50%, rgba(139, 106, 255, .09), transparent 62%),
    linear-gradient(180deg, rgba(255, 255, 255, .035), rgba(255, 255, 255, .012));
  background-size: 220% 100%, 220% 100%, 100% 100%;
  background-position: 0% 50%, 100% 50%, 0 0;
  animation: nox-scene-status-shimmer 5.6s ease-in-out infinite;
  text-align: left;
}
.nox-scene-status-frame {
  position: relative;
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border: 1px solid rgba(240, 50, 63, .26);
  border-radius: var(--nox-r-sm);
  background: rgba(240, 50, 63, .06);
  box-shadow: inset 0 0 12px rgba(240, 50, 63, .10);
  animation: nox-scene-status-breathe 3.8s ease-in-out infinite;
}
.nox-scene-status-frame svg { width: 22px; height: 22px; }
.nox-scene-status-frame svg rect,
.nox-scene-status-frame svg path { fill: none; stroke: rgba(247, 246, 248, .78); stroke-width: 1.4; stroke-linecap: round; stroke-linejoin: round; }
.nox-scene-status-frame svg circle { fill: rgba(240, 50, 63, .5); }
.nox-scene-status-spark {
  position: absolute;
  left: 2px;
  top: 7px;
  width: 4px;
  height: 4px;
  border-radius: var(--nox-r-pill);
  background: var(--nox-crimson-hot);
  opacity: 0;
  animation: nox-scene-status-drift 3.6s ease-in-out infinite;
}
.nox-scene-status-spark.is-alt { left: auto; right: -2px; top: 6px; width: 3px; height: 3px; background: #b9a4ff; animation-delay: -1.3s; animation-duration: 4.2s; }
.nox-scene-status-spark.is-low { left: -1px; top: auto; bottom: 8px; width: 3px; height: 3px; background: #f0a6ae; animation-delay: -2.5s; animation-duration: 4.6s; }
.nox-scene-status-copy { display: grid; gap: 3px; min-width: 0; }
.nox-scene-status-title { color: var(--nox-t1); font-size: 13px; font-weight: 750; line-height: 1.35; }
.nox-scene-status-sub { color: var(--nox-t3); font-size: 11.5px; line-height: 1.4; }

@keyframes nox-scene-status-shimmer {
  0%, 100% { background-position: 0% 50%, 100% 50%, 0 0; }
  50% { background-position: 100% 50%, 0% 50%, 0 0; }
}
@keyframes nox-scene-status-breathe {
  0%, 100% { transform: scale(1); opacity: .84; }
  50% { transform: scale(1.035); opacity: 1; }
}
@keyframes nox-scene-status-drift {
  0% { opacity: 0; transform: translate3d(0, 3px, 0) scale(.8); }
  45% { opacity: .8; }
  100% { opacity: 0; transform: translate3d(0, -7px, 0) scale(1.05); }
}

@media (max-width: 420px) {
  .nox-scene-status { max-width: 100%; gap: 10px; padding: 9px 12px; }
  .nox-scene-status-frame { width: 36px; height: 36px; }
}

/* The card may rest, never fade: with animation off the copy is already fully readable
   and the sparkles hold a single quiet opacity instead of parking on their 0% frame. */
@media (prefers-reduced-motion: reduce) {
  .nox-composer-status-scene,
  .nox-scene-status,
  .nox-scene-status-frame,
  .nox-scene-status-spark { animation: none !important; transition: none !important; }
  .nox-scene-status-frame { opacity: 1; }
  .nox-scene-status-spark { opacity: .45; }
}

.chat-input {
  display: flex;
  align-items: flex-end;
  gap: 8px;
  margin: 10px 14px calc(12px + env(safe-area-inset-bottom));
  padding: 6px 6px 6px 16px;
  border: 1px solid var(--nox-line);
  border-radius: 24px;
  background: var(--nox-s1);
  transition: border-color .18s ease, box-shadow .18s ease;
}
.chat-input:focus-within { border-color: #71717a; box-shadow: none; }
.chat-input textarea {
  display: block;
  flex: 1;
  min-width: 0;
  min-height: 44px;
  max-height: 132px;
  padding: 13px 0 4px;
  border: 0;
  outline: none;
  background: transparent;
  color: var(--nox-t1);
  font-size: 15px;
  line-height: 1.5;
  resize: none;
  overflow-y: auto;
}
.chat-input textarea::placeholder { color: var(--nox-t3); }
.chat-input textarea:disabled { opacity: .5; }

/* min-width:0 is load-bearing: without it the bar's automatic minimum size is its
   min-content, the nowrap cost note reports its full text width, and the bar refuses
   to shrink — which pushed the send button outside the pill on a 390px viewport. */
.nox-composer-bar { display: flex; align-items: center; gap: 2px; min-width: 0; }
.nox-composer-bar button {
  display: grid;
  place-items: center;
  flex: 0 0 38px;
  width: 38px;
  height: 38px;
  padding: 0;
  border: 0;
  border-radius: var(--nox-r-pill);
  background: transparent;
  color: var(--nox-t2);
  transition: background .16s ease, color .16s ease, transform .14s ease;
}
.nox-composer-bar button > i { font-size: 19px; line-height: 1; }
.nox-composer-bar button:hover:not(:disabled) { background: rgba(255, 255, 255, .09); color: #fff; }
.nox-composer-bar button:active:not(:disabled) { transform: scale(.92); }
.nox-composer-bar button:disabled { opacity: .4; cursor: default; }
.nox-composer-bar .nox-create-btn { color: var(--nox-gold); }
.nox-composer-bar .nox-create-btn:hover:not(:disabled) { background: rgba(243, 214, 140, .14); }
.nox-composer-bar .nox-create-btn.is-setting-off { opacity: .45; }
.nox-composer-bar .nox-cost-note {
  flex: 1;
  min-width: 0;
  margin: 0;
  padding: 0 6px;
  overflow: hidden;
  color: var(--nox-t3);
  font-size: 11.5px;
  font-weight: 650;
  text-align: right;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.nox-composer-bar .nox-send-btn {
  flex: 0 0 42px;
  width: 42px;
  height: 42px;
  margin-left: 4px;
  background: var(--nox-crimson);
  color: #fff;
  box-shadow: none;
}
.nox-composer-bar .nox-send-btn:hover:not(:disabled) { background: linear-gradient(135deg, var(--nox-crimson-hot), var(--nox-crimson)); }
.nox-composer-bar .nox-send-btn > i { font-size: 20px; }

/* ==========================================================================
   Settings drawer
   ========================================================================== */

.nox-settings-panel {
  position: fixed;
  z-index: 50;
  top: 0;
  right: 0;
  bottom: 0;
  width: min(340px, 92vw);
  height: 100%;
  padding: 0 20px 26px;
  overflow-y: auto;
  border-left: 1px solid var(--nox-line);
  background: var(--nox-glass-strong);
  backdrop-filter: blur(26px) saturate(1.2);
  -webkit-backdrop-filter: blur(26px) saturate(1.2);
  opacity: 0;
  visibility: hidden;
  transform: translateX(100%);
  transition: transform .22s ease, opacity .22s ease, visibility .22s;
}
body.nox-settings-open .nox-settings-panel { opacity: 1; visibility: visible; transform: translateX(0); }
.nox-settings-backdrop {
  position: fixed;
  z-index: 40;
  inset: 0;
  border: 0;
  background: rgba(0, 0, 0, .62);
  opacity: 0;
  visibility: hidden;
  transition: opacity .22s ease, visibility .22s;
}
body.nox-settings-open .nox-settings-backdrop { opacity: 1; visibility: visible; }

.nox-settings-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 20px 0 16px; }
.nox-settings-home { display: inline-flex; align-items: center; gap: 9px; text-decoration: none; color: var(--nox-t1); }
.nox-settings-home img { display: block; }
.nox-settings-wordmark { height: 20px; width: auto; }
.nox-settings-head button {
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  border: 1px solid var(--nox-line);
  border-radius: var(--nox-r-pill);
  background: rgba(255, 255, 255, .05);
  color: var(--nox-t2);
}
.nox-settings-head button:hover { background: rgba(255, 255, 255, .12); color: #fff; }

.nox-active-setup {
  position: relative;
  display: grid;
  gap: 4px;
  width: 100%;
  margin-bottom: 20px;
  padding: 16px 40px 16px 16px;
  border: 1px solid var(--nox-crimson-line);
  border-radius: var(--nox-r-lg);
  background: linear-gradient(135deg, rgba(240, 50, 63, .16), rgba(240, 50, 63, .04));
  color: var(--nox-t1);
  text-align: left;
}
.nox-active-setup > span { display: inline-flex; align-items: center; gap: 6px; color: var(--nox-crimson); font-size: 10.5px; font-weight: 850; letter-spacing: .1em; }
.nox-active-setup strong { font-size: 16px; font-weight: 800; }
.nox-active-setup small { color: var(--nox-t2); font-size: 12.5px; }
.nox-active-setup > i { position: absolute; right: 16px; top: 50%; transform: translateY(-50%); color: var(--nox-t3); font-size: 18px; }
.nox-active-setup:hover { border-color: rgba(240, 50, 63, .45); }

.nox-settings-group { display: grid; gap: 2px; padding: 4px 0 18px; }
.nox-settings-group h2 {
  padding: 8px 4px;
  color: var(--nox-t3);
  font-size: 11px;
  font-weight: 800;
  letter-spacing: .1em;
  text-transform: uppercase;
}
.nox-settings-group button {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  min-height: 46px;
  padding: 0 12px;
  border: 0;
  border-radius: var(--nox-r-sm);
  background: transparent;
  color: var(--nox-t1);
  font-size: 14.5px;
  font-weight: 650;
  text-align: left;
  transition: background .16s ease;
}
.nox-settings-group button:hover { background: rgba(255, 255, 255, .07); }
.nox-settings-group button > i { flex: none; width: 20px; color: var(--nox-t2); font-size: 18px; text-align: center; }
.nox-setting-value { margin-left: auto; color: var(--nox-t3); font-size: 12.5px; font-weight: 650; }
.nox-setting-switch > span {
  position: relative;
  flex: none;
  width: 42px;
  height: 24px;
  margin-left: auto;
  border-radius: var(--nox-r-pill);
  background: rgba(255, 255, 255, .14);
  transition: background .2s ease;
}
.nox-setting-switch > span::after {
  content: '';
  position: absolute;
  top: 3px;
  left: 3px;
  width: 18px;
  height: 18px;
  border-radius: var(--nox-r-pill);
  background: #fff;
  transition: transform .2s ease;
}
.nox-setting-switch[aria-pressed="true"] > span { background: var(--nox-crimson); }
.nox-setting-switch[aria-pressed="true"] > span::after { transform: translateX(18px); }

.nox-start-setting button { justify-content: space-between; }
.nox-start-setting button > i { margin-left: auto; }

.nox-story-journal { margin-bottom: 18px; padding: 14px 16px; border: 1px solid var(--nox-line); border-radius: var(--nox-r-md); background: rgba(255, 255, 255, .03); }
.nox-story-journal summary { color: var(--nox-t1); font-size: 14px; font-weight: 750; cursor: pointer; }
.nox-story-journal summary span { color: var(--nox-crimson); }
.journal-storage { margin: 10px 0; color: var(--nox-t3); font-size: 11.5px; line-height: 1.6; }
#journalContent { display: grid; gap: 8px; }
#journalContent h3 { color: var(--nox-t2); font-size: 12.5px; font-weight: 800; }
#journalContent p { color: var(--nox-t2); font-size: 13px; line-height: 1.65; }

.nox-settings-credit {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 16px;
  border: 1px solid var(--nox-line);
  border-radius: var(--nox-r-md);
  background: rgba(243, 214, 140, .06);
}
.nox-settings-credit > span { color: var(--nox-t2); font-size: 13px; }
.nox-settings-credit strong { display: inline-flex; align-items: center; gap: 6px; color: var(--nox-gold); font-size: 15px; }
.nox-settings-credit b { font-size: 16px; font-weight: 850; }
.nox-settings-note { padding-top: 14px; color: var(--nox-t3); font-size: 11.5px; line-height: 1.7; }

/* ==========================================================================
   Account / login surfaces
   ========================================================================== */

.nox-login-card { display: grid; gap: 14px; padding: 18px; border: 1px solid var(--nox-line); border-radius: var(--nox-r-md); background: var(--nox-s2); }
.nox-login-card > p { color: var(--nox-t2); font-size: 14px; font-weight: 650; line-height: 1.55; }
.nox-login-options { display: grid; gap: 10px; }
.nox-login-options button {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  min-height: 46px;
  border: 1px solid rgba(0, 0, 0, .12);
  border-radius: var(--nox-r-md);
  background: #fff;
  color: #1a1a1c;
  font-size: 14px;
  font-weight: 700;
  transition: transform .14s ease, box-shadow .16s ease;
}
.nox-login-options button:hover { box-shadow: 0 6px 20px rgba(0, 0, 0, .28); }
.nox-login-options button:active { transform: scale(.98); }
.nox-login-options button:disabled { opacity: .6; cursor: progress; }
.nox-login-options img { width: 20px; height: 20px; object-fit: contain; }
.nox-login-options .is-google img { width: 26px; height: 26px; margin: 0 -3px; }
.nox-login-note { color: #e8a3a9; font-size: 12.5px; line-height: 1.6; }
/* 게이트와 게스트 카드의 간편 로그인: 실제로 열려 있는 제공자만 활성, 나머지는 준비 중으로 보여준다. */
.nox-login-options .is-kakao { border-color: #fee500; background: #fee500; color: #191919; }
.nox-login-options .is-kakao img { width: 22px; height: 22px; }
.nox-login-options .is-naver { border-color: #03a94d; background: #03a94d; color: #fff; }
.nox-login-options .is-naver img { width: 24px; height: 24px; }
.nox-login-options .is-apple { border-color: rgba(255, 255, 255, .28); background: #000; color: #fff; }
.nox-login-options .is-pending { opacity: .55; cursor: not-allowed; }
.nox-login-options .is-pending:hover { box-shadow: none; }
.nox-login-options .is-pending:active { transform: none; }
.nox-login-options small { margin-left: 6px; padding: 2px 6px; border-radius: 999px; background: rgba(0, 0, 0, .72); color: #fff; font-size: 10px; font-weight: 700; }
.nox-login-options .is-apple small { background: rgba(255, 255, 255, .22); }
/* 게이트의 로그인 영역은 단일 버튼에서 제공자 목록으로 바뀌었다.
   옛 알약 버튼 스타일(#chatSignIn)을 지우고 전체 폭을 쓰는 세로 스택으로 되돌린다. */
/* 로그인 시트: 게이트에서는 버튼 하나만 보이고, 제공자 선택은 이 팝업에서 한다. */
.nox-login-sheet { position: fixed; z-index: 400; inset: 0; display: flex; align-items: flex-end; justify-content: center; }
.nox-login-sheet[hidden] { display: none; }
.nox-login-sheet-backdrop { position: absolute; inset: 0; background: rgba(4, 4, 6, .72); backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px); }
.nox-login-sheet-panel {
  position: relative; width: min(420px, 100%); display: grid; gap: 12px;
  padding: 22px 20px calc(22px + env(safe-area-inset-bottom, 0px));
  border: 1px solid var(--nox-line); border-radius: 20px 20px 0 0; background: var(--nox-s2);
  box-shadow: 0 -18px 50px rgba(0, 0, 0, .55);
  animation: nox-login-sheet-in .22s cubic-bezier(.22, .8, .25, 1);
}
@keyframes nox-login-sheet-in { from { opacity: 0; transform: translateY(18px); } to { opacity: 1; transform: none; } }
.nox-login-sheet-panel > strong { color: #fff; font-size: 17px; font-weight: 800; letter-spacing: -.025em; }
.nox-login-sheet-panel > p { color: var(--nox-t2); font-size: 13.5px; line-height: 1.6; }
.nox-login-sheet-close {
  position: absolute; top: 14px; right: 14px; display: grid; place-items: center;
  width: 34px; height: 34px; padding: 0; border: 0; border-radius: 50%;
  background: rgba(255, 255, 255, .08); color: var(--nox-t2); font-size: 17px; cursor: pointer;
}
.nox-login-sheet-close:hover { background: rgba(255, 255, 255, .16); color: #fff; }
@media (min-width: 720px) {
  .nox-login-sheet { align-items: center; }
  .nox-login-sheet-panel { border-radius: 18px; }
}
@media (prefers-reduced-motion: reduce) { .nox-login-sheet-panel { animation: none; } }
#chatSignIn[hidden] { display: none; }
/* #chatLoginError is an always-present status node; empty it must not reserve a row. */
.nox-login-note:empty { display: none; }

.nox-account-card { display: grid; grid-template-columns: 38px minmax(0, 1fr); align-items: center; gap: 12px; }
.nox-account-mark {
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  border-radius: var(--nox-r-pill);
  background: rgba(240, 50, 63, .14);
  color: var(--nox-crimson-hot);
  font-size: 20px;
}
.nox-account-card strong { overflow-wrap: anywhere; color: var(--nox-t1); font-size: 15px; font-weight: 750; }
.nox-account-card button {
  grid-column: 2;
  justify-self: start;
  padding: 6px 0;
  border: 0;
  background: none;
  color: var(--nox-t3);
  font-size: 13px;
}
.nox-account-card button:hover { color: var(--nox-t1); }

/* ==========================================================================
   Navigation dialogs (created/driven by chat-navigation.js)
   ========================================================================== */

.nox-nav-dialog {
  position: fixed;
  inset: 0;
  margin: auto;
  width: min(360px, calc(100vw - 24px));
  max-height: calc(100dvh - 32px);
  overflow: auto;
  padding: 20px;
  border: 1px solid var(--nox-line-strong);
  border-radius: var(--nox-r-lg);
  background: var(--nox-s2);
  color: var(--nox-t1);
  box-shadow: var(--nox-shadow);
}
.nox-nav-dialog::backdrop { background: rgba(0, 0, 0, .68); backdrop-filter: blur(4px); }
.nox-nav-dialog header { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin-bottom: 18px; }
.nox-nav-dialog h2 { font-size: 19px; font-weight: 820; letter-spacing: -.03em; }
/* No blanket `button { color: inherit }` here: it ties on specificity with
   .nox-login-options button and, being later in the file, painted white text on the
   white provider buttons. The global reset already handles colour inheritance. */
.nox-nav-dialog header button,
.rail-search button {
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  border: 1px solid var(--nox-line);
  border-radius: var(--nox-r-sm);
  background: rgba(255, 255, 255, .05);
}
.nox-nav-dialog header button:hover,
.rail-search button:hover { background: rgba(255, 255, 255, .12); }
.nox-nav-dialog .nox-login-rail { display: block; padding: 0; border: 0; background: transparent; }
.nox-nav-dialog .nox-login-card { padding: 0; border: 0; background: transparent; }
.nox-nav-dialog :focus-visible { outline: 2px solid var(--nox-crimson-hot); outline-offset: 3px; }

.rail-search { display: flex; gap: 8px; }
.rail-search input {
  width: 100%;
  min-width: 0;
  padding: 11px 12px;
  border: 1px solid var(--nox-line);
  border-radius: var(--nox-r-sm);
  background: rgba(255, 255, 255, .05);
  color: #fff;
  font-size: 14px;
}
#railRecentStatus { padding-top: 10px; color: var(--nox-t2); font-size: 13px; line-height: 1.7; }
#railRecentStatus:empty { display: none; }
.rail-conversation {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 0;
  border-bottom: 1px solid rgba(255, 255, 255, .05);
  color: var(--nox-t1);
  text-decoration: none;
}
.rail-conversation:hover { background: rgba(255, 255, 255, .04); }
.rail-conversation img { flex: 0 0 auto; width: 52px; height: 70px; border-radius: var(--nox-r-sm); object-fit: cover; }
.rail-conversation > span { display: grid; gap: 6px; min-width: 0; }
.rail-conversation strong { font-size: 14.5px; font-weight: 750; line-height: 1.5; }
.rail-conversation small { overflow: hidden; color: var(--nox-t2); font-size: 12.5px; text-overflow: ellipsis; white-space: nowrap; }
.rail-conversation time { color: var(--nox-t3); font-size: 11.5px; }
#railRecentMore, #railRecentLogin {
  width: 100%;
  margin-top: 14px;
  padding: 13px;
  border: 1px solid var(--nox-crimson-line);
  border-radius: var(--nox-r-md);
  background: rgba(240, 50, 63, .10);
  color: var(--nox-t1);
  font-size: 13.5px;
  font-weight: 700;
}
#railRecentMore:hover, #railRecentLogin:hover { background: rgba(240, 50, 63, .2); }
.nox-account-activity {
  display: block;
  margin-top: 18px;
  padding-top: 18px;
  border-top: 1px solid var(--nox-line);
  color: var(--nox-t2);
  font-size: 13.5px;
  text-decoration: none;
}
.nox-account-activity:hover { color: var(--nox-crimson-hot); }

/* ==========================================================================
   Credit sheet, toast, media confirm, unavailable story
   ========================================================================== */

.nox-chat-sheet-backdrop {
  position: fixed;
  z-index: 100;
  inset: 0;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  background: rgba(0, 0, 0, .72);
  backdrop-filter: blur(4px);
  opacity: 0;
  visibility: hidden;
  transition: .22s ease;
}
.nox-chat-sheet-backdrop.open { opacity: 1; visibility: visible; }
.nox-chat-sheet {
  position: relative;
  width: min(100%, 520px);
  padding: 30px 22px calc(24px + env(safe-area-inset-bottom));
  border: 1px solid var(--nox-line-strong);
  border-bottom: 0;
  border-radius: 24px 24px 0 0;
  background: var(--nox-s2);
  color: var(--nox-t1);
  box-shadow: 0 -24px 60px rgba(0, 0, 0, .5);
  transform: translateY(26px);
  transition: transform .25s ease;
}
.nox-chat-sheet-backdrop.open .nox-chat-sheet { transform: none; }
.nox-chat-sheet-close { position: absolute; top: 12px; right: 16px; border: 0; background: none; color: var(--nox-t3); }
.nox-chat-sheet-close i { font-size: 20px; }
.nox-chat-sheet > p { margin-bottom: 8px; color: var(--nox-crimson); font-size: 10.5px; font-weight: 850; letter-spacing: .1em; }
.nox-chat-sheet h2 { margin-bottom: 8px; font-size: 25px; font-weight: 800; letter-spacing: -.04em; line-height: 1.3; }
.nox-chat-sheet > span { display: block; margin-bottom: 18px; color: var(--nox-t2); font-size: 13px; }
.nox-chat-sheet > span strong { color: var(--nox-gold); }
.nox-chat-sheet > button[data-charge] {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  margin: 8px 0;
  padding: 16px;
  border: 1px solid var(--nox-line);
  border-radius: var(--nox-r-md);
  background: var(--nox-s3);
  color: #fff;
}
.nox-chat-sheet > button[data-charge]:hover { border-color: var(--nox-crimson-line); }
.nox-chat-sheet b { font-size: 14.5px; font-weight: 800; }
.nox-chat-sheet b small { margin-left: 6px; padding: 3px 6px; border-radius: 4px; background: var(--nox-crimson); font-size: 9px; }
.nox-chat-sheet em { color: var(--nox-t1); font-size: 13.5px; font-style: normal; font-weight: 800; }
.nox-chat-sheet > small { display: block; margin-top: 14px; color: var(--nox-t3); font-size: 11.5px; line-height: 1.6; text-align: center; }

.nox-chat-toast {
  position: fixed;
  z-index: 150;
  left: 50%;
  bottom: 100px;
  max-width: calc(100% - 32px);
  padding: 12px 18px;
  border: 1px solid var(--nox-line-strong);
  border-radius: var(--nox-r-pill);
  background: var(--nox-s2);
  color: #fff;
  font-size: 13px;
  font-weight: 700;
  opacity: 0;
  pointer-events: none;
  transform: translate(-50%, 10px);
  transition: .2s ease;
  white-space: nowrap;
}
.nox-chat-toast.show { opacity: 1; transform: translate(-50%, 0); }

.nox-media-confirm {
  width: min(380px, calc(100vw - 32px));
  padding: 26px 22px 20px;
  border: 1px solid var(--nox-line-strong);
  border-radius: var(--nox-r-lg);
  background: var(--nox-s2);
  color: var(--nox-t1);
  box-shadow: var(--nox-shadow);
}
.nox-media-confirm::backdrop { background: rgba(0, 0, 0, .7); backdrop-filter: blur(4px); }
.nox-media-confirm-icon {
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  margin: 0 auto 14px;
  border-radius: var(--nox-r-pill);
  background: linear-gradient(135deg, var(--nox-crimson), var(--nox-crimson-deep));
  color: #fff;
  font-size: 22px;
  box-shadow: var(--nox-glow);
}
.nox-media-confirm h2 { margin-bottom: 10px; font-size: 20px; font-weight: 800; text-align: center; }
.nox-media-confirm p { margin-bottom: 12px; color: var(--nox-t2); font-size: 13.5px; line-height: 1.65; text-align: center; }
.nox-media-confirm > form > strong { display: block; margin-bottom: 18px; color: var(--nox-gold); font-size: 15px; text-align: center; }
.nox-media-confirm > form > div { display: flex; gap: 10px; }
.nox-media-confirm button {
  flex: 1;
  min-height: 46px;
  border: 1px solid var(--nox-line);
  border-radius: var(--nox-r-md);
  background: rgba(255, 255, 255, .06);
  color: var(--nox-t1);
  font-size: 14px;
  font-weight: 750;
}
.nox-media-confirm button:hover { background: rgba(255, 255, 255, .12); }
#mediaConfirmAccept { border-color: transparent; background: linear-gradient(135deg, var(--nox-crimson), #a5182a); color: #fff; }

.nox-unavailable-story { display: grid; place-content: center; justify-items: center; gap: 14px; min-height: 100dvh; padding: 32px; text-align: center; }
.nox-unavailable-story h1 { font-size: 26px; font-weight: 850; letter-spacing: -.03em; }
.nox-unavailable-story p { color: var(--nox-t2); font-size: 15px; line-height: 1.7; }
.nox-unavailable-story a {
  display: inline-flex;
  align-items: center;
  min-height: 46px;
  padding: 0 22px;
  border-radius: var(--nox-r-pill);
  background: linear-gradient(135deg, var(--nox-crimson), #a5182a);
  color: #fff;
  font-size: 14.5px;
  font-weight: 750;
  text-decoration: none;
}

/* ==========================================================================
   Desktop
   ========================================================================== */

.chat-divider { display: none; }
@media (min-width: 640px) {
  body { padding: 0; }
  #chatRoot { background: #09090b; }
  .nox-chat-workspace { display: grid; grid-template-columns: 0 minmax(0, 1fr); width: 100%; height: 100dvh; margin: 0; border: 0; border-radius: 0; overflow: hidden; box-shadow: none; }
  .nox-icon-rail { display: none; }
  #chatRoot { display: grid; grid-column: 2; grid-template-columns: var(--chat-columns, minmax(0, 44fr) 1px minmax(0, 56fr)); grid-template-rows: 56px auto minmax(0, 1fr) auto; gap: 0; width: 100%; max-width: none; height: 100%; justify-self: stretch; padding: 0 16px 0 0; margin: 0; border: 0; border-radius: 0; box-shadow: none; }
  .chat-topbar { grid-column: 1 / -1; grid-row: 1; min-height: 56px; padding: 8px; gap: 4px; background: transparent; backdrop-filter: none; border: 0; }
  .chat-topbar .topbar-btn { width: 40px; height: 40px; }
  .topbar-avatar, .topbar-status, .topbar-name em, #resetButton { display: none; }
  .topbar-name b { font-size: 16px; font-weight: 600; }
  #chatRoot #characterHero { grid-column: 1; grid-row: 2 / -1; width: 100%; height: auto; min-height: 0; max-height: none; margin: 0; border: 0; border-radius: 0; align-self: stretch; }
  #chatRoot #characterHero #characterImage { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: center 22%; filter: none; opacity: 1; }
  #chatRoot #characterHero #characterImage.is-wide { object-position: 75% 22%; }
  #chatRoot #characterHero .nox-story-caption, #characterStageToggle, #characterHero .nox-chat-gradient { display: none; }
  #chatRoot #characterHero .stage-gallery-controls { display: flex; align-items: center; gap: 2px; inset: 12px auto auto 12px; padding: 3px; width: max-content; height: 36px; border-radius: 12px; background: #18181bd9; }
  #chatRoot #characterHero .stage-gallery-controls button { position: static; width: 28px; height: 28px; transform: none; border: 0; background: transparent; box-shadow: none; backdrop-filter: none; }
  #chatRoot #characterHero .stage-gallery-controls span { position: static; transform: none; max-width: 88px; overflow: hidden; text-overflow: ellipsis; padding: 0 3px; border: 0; background: transparent; font-size: 11px; backdrop-filter: none; }
  #chatRoot #characterHero .stage-gallery-controls .stage-follow { width: auto; padding: 0 8px; font-size: 11px; color: #fff; background: #ffffff16; }
  #chatRoot #characterHero .stage-gallery-controls .stage-follow[hidden] { display: none; }
  #chatRoot #characterHero .stage-feedback { display: none; }
  #chatRoot #characterHero[data-reply-state="waiting"] .stage-feedback { display: block; top: 58px; bottom: auto; right: 12px; }
  .chat-divider { display: flex; position: relative; z-index: 3; grid-column: 2; grid-row: 2 / -1; align-items: center; justify-content: center; width: 1px; background: #ffffff0d; cursor: col-resize; touch-action: none; outline: 0; }
  .chat-divider::before { content: ''; position: absolute; inset: 0 -6px; }
  .chat-divider::after { content: ''; width: 3px; height: 22px; flex: none; border-radius: 2px; background: #71717a; }
  .chat-divider:focus-visible::after, .chat-divider:hover::after, .is-resizing .chat-divider::after { height: 36px; background: #d4d4d8; }
  .is-resizing { cursor: col-resize; user-select: none; }
  .is-resizing #characterImage { pointer-events: none; }
  #conversationContextButton { display: none; }
  .nox-ai-availability { grid-column: 3; grid-row: 2; margin: 8px 12px; }
  #chatRoot .chat-messages { grid-column: 3; grid-row: 3; width: 100%; margin: 0; padding: 16px 24px 16px 16px; }
  #chatRoot .chat-composer { grid-column: 3; grid-row: 4; width: 100%; margin: 0; padding: 0 12px 12px; max-height: none; overflow: visible; background: transparent; backdrop-filter: none; border: 0; }
  .nox-settings-panel { position: fixed; width: 340px; border-radius: 0; }
  .nox-recent-dialog { position: fixed; left: 64px; top: 12px; bottom: 12px; right: auto; margin: 0; height: auto; max-height: none; }
  .nox-account-dialog { position: fixed; left: 64px; bottom: 12px; top: auto; right: auto; margin: 0; }
  .nox-chat-toast { bottom: 120px; }
}
@media (min-width: 768px) {
  .nox-chat-workspace { grid-template-columns: 64px minmax(0, 1fr); }
  .nox-icon-rail { display: flex; flex-direction: column; align-items: center; gap: 12px; padding: 16px 10px; background: transparent; }
  .nox-icon-rail a, .nox-icon-rail button { display: grid; place-items: center; flex: 0 0 44px; width: 44px; height: 44px; border: 0; border-radius: 12px; background: transparent; color: #a1a1aa; font-size: 22px; text-decoration: none; }
  .nox-icon-rail img { width: 28px; height: 28px; object-fit: contain; }
  .nox-icon-rail a:hover, .nox-icon-rail button:hover { background: #ffffff0d; color: #fff; }
  #railAccountButton { margin-top: auto; }
}

/* ==========================================================================
   Small screens and short viewports
   ========================================================================== */

/* Mobile uses the live Caveduck pattern: a fixed portrait behind the transcript,
   with an eye button that reveals the unobstructed gallery. */
.mobile-portrait-toggle { display: none; }
@media (max-width: 639px) {
  .nox-chat-workspace, #chatRoot { height: var(--chat-viewport-height, 100dvh); }
  #chatRoot { isolation: isolate; background: #17191a; }
  #chatRoot #characterHero {
    position: absolute; inset: 0; z-index: -1;
    width: 100%; height: 100%; min-height: 0; max-height: none;
    border: 0; container-type: normal; pointer-events: none;
  }
  #chatRoot #characterHero #characterImage {
    inset: 0; width: 100%; height: 100%; object-fit: cover;
    object-position: center 22%; opacity: 1; filter: none;
  }
  /* Prose has no bubble: keep it readable over even the lightest artwork. */
  #chatRoot #characterHero #characterImage.is-wide { object-position: 75% 22%; }
  body.nox-narration-novel #chatRoot:not(.is-portrait-view) #characterHero #characterImage { filter: brightness(.3); }
  #characterHero::before { inset: 0; }
  #chatRoot #characterHero .nox-chat-gradient {
    position: absolute; inset: 0; z-index: -1;
    background: linear-gradient(180deg, rgba(0,0,0,.35), rgba(0,0,0,.16) 35%, rgba(0,0,0,.5));
  }
  #characterHero .nox-story-caption, #characterStageToggle,
  #characterHero .stage-feedback, #characterHero .stage-gallery-controls,
  #conversationContextButton { display: none; }
  .chat-topbar {
    order: 0; min-height: calc(48px + env(safe-area-inset-top)); gap: 4px; padding: calc(4px + env(safe-area-inset-top)) 4px 4px;
    border: 0; background: linear-gradient(rgba(0,0,0,.38), transparent);
    backdrop-filter: none; -webkit-backdrop-filter: none;
  }
  .topbar-avatar, .topbar-status, .topbar-name em, #resetButton { display: none; }
  .chat-topbar .topbar-btn { width: 40px; height: 40px; color: white; }
  .mobile-portrait-toggle { display: grid; }
  .topbar-name b { font-size: 16px; font-weight: 600; text-shadow: 0 1px 5px #000; }
  .nox-credit-btn { min-width: 44px; padding: 0 8px; background: rgba(0,0,0,.3); border: 0; }
  #chatRoot .chat-messages {
    order: 1; position: relative; flex: 1 1 0; min-height: 0;
    padding: 16px; gap: 24px; background: transparent;
    scroll-padding: 20px;
  }
  .msg { gap: 0; flex-shrink: 0; }
  .msg-avatar, .msg-author, .msg-time { display: none; }
  .msg-body { max-width: 100%; gap: 8px; }
  .msg-user .msg-body { max-width: 88%; }
  .msg-bot .bubble, .msg-user .bubble {
    padding: 15px 17px; border: 0; border-radius: 18px;
    background: rgba(29,31,33,.82); color: #f7f6f8; box-shadow: none;
    font-size: 17px; line-height: 1.8; font-weight: 400;
  }
  .msg-user .bubble { background: rgba(43,43,43,.9); color: #ffd76c; }
  body.nox-narration-novel .msg-bot .bubble { padding: 0; background: transparent; border: 0; border-radius: 0; font-size: 17px; line-height: 1.9; text-shadow: 0 1px 6px #000b; }
  .nox-speech-button { background: rgba(20,22,24,.65); color: #d4d4d8; }
  #chatRoot .nox-ai-availability {
    order: 2; flex: none; display: flex; align-items: center; gap: 10px;
    margin: 0 12px 6px; padding: 10px 12px; border-radius: 16px;
    background: rgba(26,27,29,.93); border: 1px solid rgba(255,255,255,.12);
  }
  .nox-ai-icon { display: none; }
  .nox-ai-copy { flex: 1; min-width: 0; }
  .nox-ai-copy strong { font-size: 13px; line-height: 1.4; }
  .nox-ai-copy span { font-size: 11px; line-height: 1.4; }
  .nox-ai-actions { margin: 0; flex: none; }
  .nox-ai-actions button { height: 40px; padding: 0 12px; font-size: 12px; }
  #chatRoot .chat-composer {
    order: 3; flex: none; max-height: 45%; border: 0;
    padding-bottom: env(safe-area-inset-bottom); background: transparent;
    backdrop-filter: none; -webkit-backdrop-filter: none;
  }
  .quick-replies { padding: 4px 12px 6px; gap: 8px; }
  .chip { font-size: 13px; font-weight: 400; padding: 9px 13px; background: rgba(31,32,34,.9); color: #eee; border-color: rgba(255,255,255,.10); }
  .chat-input { flex-direction: column; align-items: stretch; gap: 2px; margin: 0 12px 8px; padding: 7px 7px 6px 14px; background: rgba(42,43,45,.96); border-radius: 16px; }
  .chat-input textarea { width: 100%; flex: none; min-height: 38px; max-height: 112px; padding: 7px 0 0; font-size: 17px; }
  .chat-input textarea::placeholder { color: #aaa9b0; }
  .nox-composer-bar { width: 100%; }
  .nox-composer-bar button { width: 40px; height: 40px; flex-basis: 40px; }
  .nox-composer-bar .nox-cost-note { font-size: 11px; font-weight: 400; padding-inline: 4px; white-space: normal; line-height: 1.4; color: #b9b6bf; }
  .nox-composer-bar .nox-send-btn { width: 44px; height: 44px; flex-basis: 44px; box-shadow: none; }
  #chatRoot.is-portrait-view .chat-messages,
  #chatRoot.is-portrait-view .chat-composer,
  #chatRoot.is-portrait-view .nox-ai-availability,
  #chatRoot.is-portrait-view .topbar-title,
  #chatRoot.is-portrait-view #creditButton,
  #chatRoot.is-portrait-view #settingsButton { display: none; }
  #chatRoot.is-portrait-view .mobile-portrait-toggle { margin-left: auto; background: rgba(0,0,0,.45); }
  #chatRoot.is-portrait-view #characterHero { pointer-events: auto; }
  #chatRoot.is-portrait-view #characterHero #characterImage { object-fit: contain; object-position: center; }
  #chatRoot.is-portrait-view #characterHero .nox-chat-gradient { display: none; }
  #chatRoot.is-portrait-view #characterHero .stage-gallery-controls { display: flex; position: absolute; inset: auto 0 calc(20px + env(safe-area-inset-bottom)); justify-content: center; gap: 12px; }
  #chatRoot.is-portrait-view #characterHero .stage-gallery-controls button { position: static; transform: none; width: 44px; height: 44px; background: rgba(0,0,0,.7); }
  #chatRoot.is-portrait-view #characterHero .stage-gallery-controls span { position: static; transform: none; align-self: center; background: rgba(0,0,0,.7); }
}
@media (max-width: 639px) and (max-height: 520px) {
  .chat-topbar { min-height: 48px; padding-block: 2px; }
  .nox-ai-copy span { display: none; }
  #chatRoot .nox-ai-availability { padding-block: 6px; }
}

/* Shared two-row composer: matches the reference's 12px inset and 36px tool row. */
.chat-composer { container-type: inline-size; }
#chatRoot .chat-input { display: flex; flex-direction: column; align-items: stretch; gap: 8px; padding: 12px; margin: 0; border: 0; border-radius: 16px; background: #333; }
#chatRoot .chat-input:focus-within { box-shadow: inset 0 0 0 1px #71717a; }
#chatRoot .chat-input textarea { width: 100%; flex: none; min-height: 32px; padding: 0; font-size: 16px; line-height: 24px; }
.nox-composer-bar { width: 100%; min-height: 36px; gap: 2px; }
.nox-composer-bar button, .nox-composer-bar .nox-send-btn { width: 36px; height: 36px; flex: 0 0 36px; margin: 0; }
.nox-composer-bar .nox-cost-note { display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto; min-width: 52px; height: 32px; gap: 4px; padding: 6px 8px; border-radius: 12px; background: #27272a; color: #e4e4e7; font-size: 12px; font-weight: 500; line-height: 20px; text-align: left; white-space: nowrap; }

.nox-composer-bar .composer-memory { display: flex; align-items: center; justify-content: center; gap: 6px; width: auto; flex-basis: auto; padding-inline: 8px; color: #d4d4d8; font-size: 13px; }
.composer-memory i { color: #ec4899; }
.nox-composer-bar #imageButton { margin-left: auto; }
.nox-composer-bar #quickRepliesToggle[aria-expanded="true"] { color: #facc15; background: #ffffff0d; }
.quick-replies { padding: 0 0 12px; gap: 8px; }
@container (max-width: 480px) {
  .composer-memory span { display: none; }
  .nox-composer-bar .composer-memory { width: 36px; flex: 0 0 36px; padding: 0; }
}
@container (max-width: 359px) {
  .nox-composer-bar button, .nox-composer-bar .nox-send-btn, .nox-composer-bar .composer-memory { width: 32px; flex-basis: 32px; }
  .nox-composer-bar .nox-cost-note { min-width: 48px; padding-inline: 6px; }
}
@media (max-width: 639px) {
  #chatRoot .chat-composer { padding: 0 12px calc(12px + env(safe-area-inset-bottom)); }
  #chatRoot .chat-input textarea { min-height: 26px; }
}

/* Measured Caveduck themes: profiles above bubbles; novel turns are full-width prose. */
#chatRoot { background-color: #1a1c1c; }
#chatRoot .chat-messages { gap: 16px; }
#chatRoot .msg { gap: 0; }
#chatRoot .msg-body { width: 100%; max-width: 100%; gap: 8px; }
#chatRoot .msg-profile { display: flex; align-items: center; gap: 8px; width: 100%; margin-bottom: -4px; }
#chatRoot .msg-avatar { display: block; width: 40px; height: 40px; margin: 0; box-shadow: none; }
#chatRoot .msg-author { display: block; padding: 0; font-size: 16px; font-weight: 400; color: #fff; }
#chatRoot .msg-time { display: none; }
#chatRoot .bubble { max-width: 85%; padding: 8px 12px; border: 0; font-size: 16px; line-height: 1.625; font-weight: 400; text-shadow: none; box-shadow: none; word-break: normal; }
#chatRoot .msg-bot .bubble { background: #262727; border-radius: 0 16px 16px; color: #d1d5db; font-style: italic; }
#chatRoot .msg-user .bubble { background: #000; border-radius: 16px 0 16px 16px; color: #93c5fd; font-style: normal; }
#chatRoot .reply-dialogue { color: #facc15; font-style: normal; }
#chatRoot .nox-scene-notebook { width: 85%; max-width: 85%; }
body.nox-narration-novel #chatRoot .msg-profile { display: none; }
body.nox-narration-novel #chatRoot .msg-user .msg-body { align-items: flex-start; }
body.nox-narration-novel #chatRoot .bubble { width: 100%; max-width: 100%; padding: 0; border-radius: 0; background: transparent; }
body.nox-narration-novel #chatRoot .nox-scene-notebook { width: 100%; max-width: 100%; }
body.nox-cards-hidden #chatRoot .nox-scene-notebook { display: none; }
body.nox-background-hidden #chatRoot #characterHero,
body.nox-background-hidden #chatRoot #chatDivider,
body.nox-background-hidden #chatRoot #mobilePortraitToggle { display: none; }
body.nox-background-hidden #chatRoot .chat-topbar { background: #1a1c1c; }
body.nox-background-hidden #chatRoot { grid-template-columns: minmax(0, 1fr); }
body.nox-background-hidden #chatRoot .chat-messages,
body.nox-background-hidden #chatRoot .chat-composer,
body.nox-background-hidden #chatRoot .nox-ai-availability { grid-column: 1; }
body.nox-chat-font-large #chatRoot .bubble { font-size: 18px; }
.chat-display-settings { margin: 0 0 16px; padding-bottom: 16px; border-bottom: 1px solid #ffffff1a; }
.chat-display-settings > summary { padding: 10px 0; font-size: 15px; font-weight: 600; cursor: pointer; }
.chat-display-settings .chat-theme-options { display: flex; gap: 4px; padding: 4px; border: 1px solid #ffffff1a; border-radius: 8px; }
.chat-display-settings .chat-theme-options button { flex: 1; justify-content: center; min-height: 36px; border-radius: 5px; color: #d4d4d8; }
.chat-display-settings .chat-theme-options button[aria-pressed="true"] { background: #55585e; color: #fff; }
.chat-display-settings > p { margin: 10px 0; color: #a1a1aa; font-size: 12px; line-height: 1.5; }
.chat-display-settings > label { display: flex; align-items: center; justify-content: space-between; gap: 8px; min-height: 42px; font-size: 14px; color: #e4e4e7; cursor: pointer; }
.chat-display-settings small { display: block; font-size: 11px; color: #a1a1aa; }
.chat-display-settings input { width: 18px; height: 18px; accent-color: #db2777; }
.chat-display-settings input:disabled { opacity: .45; }
.chat-display-settings select { padding: 6px 10px; border: 1px solid #ffffff26; border-radius: 6px; color: #eee; background: #27272a; }
/* Generated scenes read as pictures, not thumbnails: a natural-ratio image at a
   readable size in both narration modes, with no reveal step to unlock it. */
#chatRoot .nox-message-media[data-kind="image"][data-generated="true"] { width: min(320px, 100%); max-width: 100%; margin-block: 8px; }
#chatRoot .nox-message-media[data-kind="image"][data-generated="true"] img { max-height: none; object-fit: contain; }
@media (max-width: 639px) {
  #chatRoot .bubble { max-width: 100%; font-size: 14px; }
  #chatRoot .msg-author { font-size: 14px; }
  #chatRoot .nox-scene-notebook { width: 100%; max-width: 100%; }
  #chatRoot .nox-message-media[data-kind="image"][data-generated="true"] { width: min(280px, 100%); }
  body.nox-chat-font-large #chatRoot .bubble { font-size: 17px; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    scroll-behavior: auto !important;
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
  /* The stage must snap, not merely transition quickly. `transition-duration: .01ms`
     still starts from the previous value on the frame the class flips, so an immediate
     measurement — the stage toggle, or test-conversation-media.cjs:125 — reads stale. */
  #chatRoot .chat-context { transition: none; }
}

/* Shared player for generated voice, saved messages and recording previews.
   One slim row: a 30px rose circle inside a 44px hit target, a 44px-high seek hit
   area over the 3px visual track, and an inline elapsed/total stamp. The label lives
   on the group's aria-label only, and there is deliberately no visible title.
   Grid, not wrap: the controls must stay on one row (nowrap), yet a nonempty error
   has to take a row of its own. `44px minmax(0,1fr)` plus the error's `1 / -1`
   span is what does both; `:empty { display: none }` keeps the row from appearing
   until something actually fails. */
.nox-audio-player { display: grid; grid-template-columns: 44px minmax(0, 1fr); align-items: center; column-gap: 10px; row-gap: 6px; width: min(300px,100%); max-width: 100%; box-sizing: border-box; padding: 0 12px 0 0; min-height: 44px; border: 1px solid #ffffff14; border-radius: 12px; background: #242426b8; color: #f5f5f6; font-style: normal; }
.nox-audio-player audio { display: none !important; }
.nox-audio-player .nox-audio-toggle { grid-column: 1; display: grid; place-items: center; box-sizing: border-box; width: 44px; height: 44px; min-height: 44px; padding: 7px; border: 0; border-radius: 50%; background: #f43f57; background-clip: content-box; color: #fff; cursor: pointer; font-size: 13px; font-style: normal; }
.nox-audio-player .nox-audio-toggle:hover { background: #fb5870; background-clip: content-box; }
.nox-audio-player .nox-audio-toggle > i { line-height: 1; }
.nox-audio-track { grid-column: 2; flex: 1 1 0; min-width: 0; display: flex; align-items: center; gap: 8px; }
.nox-audio-time { flex: 0 0 auto; color: #a1a1aa; font-size: 11px; line-height: 1; white-space: nowrap; font-variant-numeric: tabular-nums; font-style: normal; }
/* 44px tall for the touch target; the visual track stays 3px and stays centred. */
.nox-audio-track input[type=range] { appearance: none; -webkit-appearance: none; flex: 1 1 0; display: block; min-width: 0; height: 44px; margin: 0; padding: 0; border: 0; background: transparent; cursor: pointer; touch-action: pan-y; }
.nox-audio-track input[type=range]::-webkit-slider-runnable-track { height: 3px; border-radius: 3px; background: linear-gradient(to right,#fb7185 var(--audio-progress,0%),#ffffff24 var(--audio-progress,0%)); }
.nox-audio-track input[type=range]::-webkit-slider-thumb { appearance: none; -webkit-appearance: none; width: 10px; height: 10px; margin-top: -3.5px; border: 0; border-radius: 50%; background: #fb7185; }
.nox-audio-track input[type=range]::-moz-range-track { height: 3px; border-radius: 3px; background: #ffffff24; }
.nox-audio-track input[type=range]::-moz-range-progress { height: 3px; border-radius: 3px; background: #fb7185; }
.nox-audio-track input[type=range]::-moz-range-thumb { width: 10px; height: 10px; border: 0; border-radius: 50%; background: #fb7185; }
.nox-audio-player :focus-visible { outline: 2px solid #fda4af; outline-offset: 2px; }
.nox-audio-error { grid-column: 1 / -1; flex: 0 0 100%; color: #fda4af; font-size: 12px; line-height: 1.5; font-style: normal; }
.nox-audio-error:empty { display: none; }
.nox-attachment-copy .nox-audio-player { width: 100%; margin-bottom: 6px; }

/* Full-screen image viewer. One lazily created native dialog is reused for every
   image, and it never opens a window or mints a URL of its own: the <img> borrows
   the object URL the message already holds. `object-fit: contain` keeps the whole
   picture uncropped, and the safe-area padding keeps it clear of notches and home
   indicators on a 100dvh mobile viewport. */
.nox-image-viewer {
  position: fixed;
  inset: 0;
  box-sizing: border-box;
  width: auto;
  max-width: none;
  height: 100dvh;
  max-height: 100dvh;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  color: #fff;
  overflow: hidden;
}
.nox-image-viewer::backdrop { background: rgba(0, 0, 0, .94); }
.nox-image-viewer img {
  display: block;
  box-sizing: border-box;
  width: 100%;
  height: 100%;
  padding: max(16px, env(safe-area-inset-top)) max(16px, env(safe-area-inset-right)) max(16px, env(safe-area-inset-bottom)) max(16px, env(safe-area-inset-left));
  object-fit: contain;
}
.nox-image-viewer-close {
  position: fixed;
  top: max(12px, env(safe-area-inset-top));
  right: max(12px, env(safe-area-inset-right));
  display: grid;
  place-items: center;
  box-sizing: border-box;
  width: 44px;
  height: 44px;
  min-height: 44px;
  padding: 0;
  border: 1px solid rgba(255, 255, 255, .2);
  border-radius: 50%;
  background: rgba(24, 24, 27, .72);
  color: #fff;
  cursor: pointer;
  font-size: 17px;
}
.nox-image-viewer-close:hover { background: rgba(63, 63, 70, .88); }
.nox-image-viewer :focus-visible { outline: 2px solid #fda4af; outline-offset: 2px; }

/* Simplified sidebar (2026-09-16): one settings group, the destructive reset last and tinted. */
.nox-settings-group .chat-display-settings { margin: 0 0 12px; padding-bottom: 12px; }
.nox-settings-group button.nox-setting-danger, .nox-settings-group button.nox-setting-danger > i { color: #ff8a95; }
.nox-settings-group button.nox-setting-danger { margin-top: 6px; }
