/* Lantern design tokens: midnight canvas, velvet surfaces, cobalt for
   structure and interaction, ember for warmth and story, parchment for
   narrative prose set in the serif stack. */
:root {
    --bg: #070d18;
    --bg-elevated: #0e1626;
    --sidebar-bg: #0a1120;
    --card-bg: #101a2e;
    --surface-hover: #16203a;
    --border: #223252;
    --border-soft: #1c2740;
    --text: #e7ebf4;
    --text-muted: #97a3bb;
    --text-faint: #6b7891;
    --accent: #2563eb;
    --accent-hover: #4a80f0;
    --accent-bright: #6ea8ff;
    --accent-soft: rgba(59, 115, 235, 0.14);
    --ember: #f0a35c;
    --ember-bright: #f6bd85;
    --ember-soft: rgba(240, 163, 92, 0.12);
    --parchment: #f2e9da;
    --user-bubble: #13203a;
    --danger: #ff6b6b;
    --danger-soft: rgba(255, 107, 107, 0.12);
    --ok: #4ec98f;
    --ok-soft: rgba(78, 201, 143, 0.12);
    --radius: 12px;
    --sidebar-width: 270px;
    --content-width: 768px;
    --serif: "Literata", Georgia, "Times New Roman", serif;
    font-family: "Segoe UI", system-ui, -apple-system, Roboto, Helvetica, Arial, sans-serif;
}

*, *::before, *::after {
    box-sizing: border-box;
}

html, body {
    margin: 0;
    padding: 0;
    height: 100%;
    background: var(--bg);
    color: var(--text);
    font-size: 15px;
    line-height: 1.5;
    font-family: "Segoe UI", system-ui, -apple-system, Roboto, Helvetica, Arial, sans-serif;
    -webkit-tap-highlight-color: transparent;
    color-scheme: dark;
}

a {
    color: var(--accent);
    text-decoration: none;
}

a:hover {
    text-decoration: underline;
}

.muted { color: var(--text-muted); }
.small { font-size: 0.85em; }
.warn { color: #e6b54a; }

/* Inline SVG icons (Components/Icon.razor): sized by the local font-size,
   optically aligned to the text baseline. */
.icon {
    vertical-align: -0.14em;
    flex-shrink: 0;
    display: inline-block;
}
.icon.spin { animation: icon-spin 0.9s linear infinite; }
@keyframes icon-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
    .icon.spin { animation-duration: 2s; }
}

/* Element defaults the component rules build on (browser defaults would add
   top margins to headings/paragraphs and give form controls their own font). */
h1, h2, h3, h4, h5, h6 { margin: 0 0 0.5rem; line-height: 1.2; }
h1, h2, h3 { font-weight: 600; }
h1 { font-size: calc(1.375rem + 1.5vw); }
h2 { font-size: calc(1.325rem + 0.9vw); }
h3 { font-size: calc(1.3rem + 0.6vw); }
h4 { font-size: calc(1.275rem + 0.3vw); }
h5 { font-size: 1.25rem; }
h6 { font-size: 1rem; }
@media (min-width: 1200px) {
    h1 { font-size: 2.5rem; }
    h2 { font-size: 2rem; }
    h3 { font-size: 1.75rem; }
    h4 { font-size: 1.5rem; }
}
p { margin: 0 0 1rem; }

/* FocusOnNavigate (Routes.razor) moves focus to the page's first h1 after navigation
   for screen readers; headings are never keyboard-focusable, so hide the browser's
   default focus ring it would otherwise draw around them (the "white box" around
   "How can I help?" right after signing in). */
h1:focus, h1:focus-visible { outline: none; }
code { font-size: 0.875em; }
button, input, optgroup, select, textarea { margin: 0; font-family: inherit; font-size: inherit; line-height: inherit; }
button:not(:disabled) { cursor: pointer; }
textarea { resize: vertical; }

/* ---------- App shell ---------- */
.app-shell {
    display: flex;
    height: 100vh;
    overflow: hidden;
}

.app-main {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    background:
        radial-gradient(880px 480px at 72% -18%, rgba(37, 99, 235, 0.12), transparent 66%),
        radial-gradient(620px 420px at 10% -12%, rgba(240, 163, 92, 0.06), transparent 62%),
        var(--bg);
}

/* ---------- Sidebar ---------- */
.sidebar {
    width: var(--sidebar-width);
    flex-shrink: 0;
    background:
        linear-gradient(180deg, rgba(28, 42, 74, 0.4), transparent 34%),
        var(--sidebar-bg);
    border-right: 1px solid var(--border);
    display: flex;
    flex-direction: column;
    height: 100vh;
}

.sidebar-header {
    padding: 18px 18px 6px;
    display: flex;
    align-items: center;
    gap: 10px;
}

.brand-mark {
    width: 30px;
    height: 30px;
    object-fit: contain;
    flex-shrink: 0;
    filter: drop-shadow(0 3px 6px rgba(37, 99, 235, 0.25));
}

.sidebar-header .brand {
    font-family: var(--serif);
    font-size: 1.3rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    color: var(--parchment);
}

.new-chat-btn {
    margin: 10px 14px 8px;
    padding: 10px 14px;
    background: var(--accent-soft);
    color: var(--text);
    border: 1px solid var(--accent);
    border-radius: 10px;
    cursor: pointer;
    font-size: 0.95rem;
    text-align: left;
    display: flex;
    align-items: center;
    gap: 8px;
    transition: background 0.15s;
}

.new-chat-btn:hover { background: rgba(59, 115, 235, 0.24); }
.new-chat-btn .icon { color: var(--text-muted); }
.new-chat-btn:hover .icon { color: var(--text); }

.thread-list {
    flex: 1;
    overflow-y: auto;
    padding: 6px 8px;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.thread-empty {
    padding: 14px;
    font-size: 0.9rem;
}

.thread-item {
    display: flex;
    align-items: center;
    border-radius: 8px;
    transition: background 0.12s;
}

.thread-item:hover { background: var(--bg-elevated); }
.thread-item.active {
    background: var(--ember-soft);
    box-shadow: inset 2px 0 0 var(--ember);
}

.thread-link {
    flex: 1;
    min-width: 0;
    padding: 9px 10px;
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    font-size: 0.9rem;
}

.thread-link:hover { text-decoration: none; }

/* Kind marker (adventure / character) inside a thread row. */
.thread-link .thread-kind {
    color: var(--text-faint);
    margin-right: 6px;
}

.thread-delete {
    opacity: 0;
    background: none;
    border: none;
    color: var(--text-muted);
    cursor: pointer;
    padding: 6px 8px;
    font-size: 0.85rem;
    border-radius: 6px;
}

.thread-item:hover .thread-delete { opacity: 1; }
.thread-delete:hover { color: var(--danger); }

.thread-rename {
    opacity: 0;
    background: none;
    border: none;
    color: var(--text-muted);
    cursor: pointer;
    padding: 6px 4px;
    font-size: 0.85rem;
    border-radius: 6px;
}

.thread-item:hover .thread-rename { opacity: 1; }
.thread-rename:hover { color: var(--accent, #7aa2f7); }

.thread-rename-save,
.thread-rename-cancel {
    background: none;
    border: none;
    color: var(--text-muted);
    cursor: pointer;
    padding: 6px 4px;
    font-size: 0.85rem;
    border-radius: 6px;
}

.thread-rename-save:hover { color: var(--accent, #7aa2f7); }
.thread-rename-cancel:hover { color: var(--danger); }

.thread-rename-input {
    flex: 1;
    min-width: 0;
    margin: 4px 6px;
    padding: 5px 6px;
    font-size: 0.9rem;
    color: var(--text);
    background: var(--bg-elevated);
    border: 1px solid var(--accent, #7aa2f7);
    border-radius: 6px;
    outline: none;
}

/* Story-bound conversations cluster under their world's header. */
.thread-group {
    border-left: 2px solid var(--border);
    border-radius: 2px;
    margin: 2px 0;
}

.thread-group-header {
    padding: 7px 10px 3px;
    font-size: 0.72rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.thread-group .thread-item { margin-left: 6px; }

.sidebar-footer {
    border-top: 1px solid var(--border);
    padding: 8px;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.footer-link {
    display: flex;
    align-items: center;
    gap: 9px;
    width: 100%;
    text-align: left;
    padding: 9px 12px;
    color: var(--text-muted);
    background: none;
    border: none;
    border-radius: 8px;
    cursor: pointer;
    font-size: 0.9rem;
}

.footer-link .icon { color: var(--text-faint); }
.footer-link:hover .icon, .footer-link.active .icon { color: var(--text-muted); }

.footer-link:hover { background: var(--bg-elevated); color: var(--text); text-decoration: none; }
.footer-link.active { color: var(--text); background: var(--bg-elevated); }
.logout-form { margin: 0; }
.logout-btn { font-family: inherit; }

/* ---------- Chat ---------- */
.chat {
    display: flex;
    flex-direction: column;
    height: 100vh;
}

.chat-topbar {
    height: 52px;
    flex-shrink: 0;
    border-bottom: 1px solid var(--border-soft);
    display: flex;
    align-items: center;
    padding: 0 20px;
    background: var(--bg);
}

.model-picker {
    display: flex;
    align-items: center;
    gap: 8px;
}

.model-picker label {
    color: var(--text-muted);
    font-size: 0.85rem;
}

.model-picker select {
    background: transparent;
    color: var(--text);
    border: 1px solid var(--border-soft);
    border-radius: 8px;
    padding: 6px 10px;
    font-size: 0.9rem;
    cursor: pointer;
    max-width: 340px;
    transition: border-color 0.15s, background 0.15s;
}

.model-picker select:hover:not(:disabled) {
    background: var(--bg-elevated);
    border-color: var(--border);
}

/* Ordinary (assistant) chats list model capabilities in the picker, so the
   three pickers may wrap onto a second row rather than overflow. */
.assistant-chat .chat-topbar {
    height: auto;
    min-height: 52px;
    flex-wrap: wrap;
    gap: 8px 16px;
    padding-top: calc(8px + env(safe-area-inset-top, 0px));
    padding-bottom: 8px;
}

/* Thinking + prompt pickers: inline on desktop. The chip that folds them into
   a sheet, and the sheet's Done button, only exist on phones (mobile block). */
.rpg-chip.tuning-toggle, .tuning-done { display: none; }
.tuning-pickers { display: contents; }

.messages {
    flex: 1;
    overflow-y: auto;
    padding: 24px 20px;
}

.messages-inner {
    max-width: var(--content-width);
    margin: 0 auto;
}

.empty-state {
    max-width: var(--content-width);
    margin: 12vh auto 0;
    text-align: center;
    color: var(--text-muted);
}

.empty-state h1 {
    font-family: var(--serif);
    font-size: 2.1rem;
    font-weight: 600;
    color: var(--parchment);
    margin-bottom: 12px;
}

.notice {
    display: inline-block;
    margin-top: 8px;
    padding: 10px 14px;
    border-radius: 10px;
    background: var(--bg-elevated);
}

.msg {
    display: flex;
    gap: 14px;
    padding: 18px 0;
    border-bottom: 1px solid var(--border-soft);
}

.msg:last-child { border-bottom: none; }

.msg-avatar {
    flex-shrink: 0;
    width: 30px;
    height: 30px;
    border-radius: 8px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.95rem;
    background: var(--bg-elevated);
}

.msg-user .msg-avatar { background: #16223c; }
.msg-assistant .msg-avatar {
    background: linear-gradient(135deg, #2563eb, #4a80f0);
    color: #fff;
    box-shadow: 0 5px 16px rgba(37, 99, 235, 0.25);
}

.msg-content { flex: 1; min-width: 0; }

.msg.rollback-target {
    cursor: pointer;
    border-radius: 10px;
    transition: background 0.15s, box-shadow 0.15s;
}

.msg.rollback-target:hover {
    background: var(--bg-elevated);
    box-shadow: 0 0 0 1px var(--border-soft);
}

.msg.rollback-target:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

.msg.rollback-target:hover .msg-role::after {
    content: " - Click to roll back";
    color: var(--text-faint);
    font-weight: 400;
}

.msg.rollback-selected {
    background: var(--accent-soft);
    box-shadow: inset 3px 0 0 var(--accent);
}

.msg-role {
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--text-muted);
    margin-bottom: 4px;
}

.user-text {
    white-space: pre-wrap;
    word-wrap: break-word;
    line-height: 1.6;
}

.msg-error .markdown { color: var(--danger); }

/* Per-message actions (try again / edit / roll back) — always visible but muted. */
.msg-actions { display: flex; gap: 14px; margin-top: 8px; align-items: center; }
.msg-action {
    background: none;
    border: none;
    padding: 0;
    color: var(--text-faint);
    font-size: 0.8rem;
    cursor: pointer;
    transition: color 0.15s;
}
.msg-action:hover { color: var(--text); }

.rollback-confirm {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    margin-top: 12px;
    padding: 12px 14px;
    border: 1px solid var(--border);
    border-radius: 10px;
    background: var(--card-bg);
}

.rollback-confirm strong,
.rollback-confirm span {
    display: block;
}

.rollback-confirm span {
    margin-top: 3px;
    color: var(--text-muted);
    font-size: 0.82rem;
    line-height: 1.4;
}

.rollback-actions {
    display: flex;
    flex-shrink: 0;
    gap: 8px;
}

@media (max-width: 640px) {
    .rollback-confirm {
        align-items: stretch;
        flex-direction: column;
    }

    .rollback-actions {
        justify-content: flex-end;
    }
}

/* AI-assisted message revision: a free-text instruction box hanging below
   the actions row — same framing as .rollback-confirm, stacked vertically
   to fit its textarea instead of that panel's left-text/right-buttons row. */
.revise-panel {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 12px;
    padding: 12px 14px;
    border: 1px solid var(--border);
    border-radius: 10px;
    background: var(--card-bg);
}
.revise-panel .edit-area { min-height: 64px; }

/* Inline editor for an assistant response */
.edit-area {
    width: 100%;
    min-height: 120px;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: 9px;
    color: var(--text);
    padding: 10px 12px;
    font-family: inherit;
    font-size: 0.95rem;
    line-height: 1.6;
}
.edit-area:focus { border-color: var(--accent); outline: none; }

/* Markdown body */
.markdown { line-height: 1.65; word-wrap: break-word; }
.markdown p { margin: 0 0 0.85em; }
.markdown p:last-child { margin-bottom: 0; }
.markdown ul, .markdown ol { margin: 0 0 0.85em; padding-left: 1.5em; }
.markdown li { margin: 0.2em 0; }
.markdown h1, .markdown h2, .markdown h3 { margin: 1em 0 0.5em; line-height: 1.3; }
.markdown a { text-decoration: underline; }
.markdown code {
    background: #04080f;
    border: 1px solid var(--border);
    border-radius: 5px;
    padding: 1px 5px;
    font-family: "Cascadia Code", Consolas, "Courier New", monospace;
    font-size: 0.88em;
}
.markdown pre {
    background: #04080f;
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 14px 16px;
    overflow-x: auto;
    margin: 0 0 0.85em;
}
.markdown pre code { background: none; border: none; padding: 0; font-size: 0.86em; }
.markdown blockquote {
    margin: 0 0 0.85em;
    padding-left: 14px;
    border-left: 3px solid var(--border);
    color: var(--text-muted);
}
.markdown table { border-collapse: collapse; margin-bottom: 0.85em; }
.markdown th, .markdown td { border: 1px solid var(--border); padding: 6px 10px; }

/* Typing indicator */
.typing { display: inline-flex; gap: 4px; padding: 6px 0; }
.typing span {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--text-muted);
    animation: typing 1.2s infinite ease-in-out;
}
.typing span:nth-child(2) { animation-delay: 0.18s; }
.typing span:nth-child(3) { animation-delay: 0.36s; }

@keyframes typing {
    0%, 60%, 100% { transform: translateY(0); opacity: 0.4; }
    30% { transform: translateY(-4px); opacity: 1; }
}

/* Composer */
.composer-wrap {
    flex-shrink: 0;
    padding: 12px 20px 18px;
    background: linear-gradient(to top, var(--bg) 70%, transparent);
}

/* Way back to the live edge after scrolling up mid-reply. Sits just above the
   composer, centred on the same content column. */
.jump-latest {
    display: flex;
    align-items: center;
    gap: 6px;
    margin: 0 auto 8px;
    padding: 6px 14px;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--bg-elevated);
    color: var(--text);
    font-size: 0.85rem;
    font-weight: 600;
    cursor: pointer;
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.28);
    transition: border-color 0.15s, color 0.15s;
}

.jump-latest:hover {
    border-color: var(--accent);
    color: var(--accent-bright, var(--accent));
}

.composer {
    max-width: var(--content-width);
    margin: 0 auto;
    display: flex;
    align-items: flex-end;
    gap: 8px;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: 16px;
    padding: 8px 8px 8px 16px;
    transition: border-color 0.15s;
}

.composer:focus-within {
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-soft), 0 14px 42px rgba(2, 12, 27, 0.34);
}

.composer textarea {
    flex: 1;
    resize: none;
    border: none;
    outline: none;
    background: transparent;
    color: var(--text);
    font-family: inherit;
    font-size: 1rem;
    line-height: 1.5;
    max-height: 220px;
    padding: 6px 0;
}

.composer textarea::placeholder { color: var(--text-faint); }
.composer textarea:disabled { opacity: 0.5; }

.composer-btn {
    flex-shrink: 0;
    width: 38px;
    height: 38px;
    border-radius: 10px;
    border: none;
    cursor: pointer;
    font-size: 1rem;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background 0.15s, opacity 0.15s;
}

.composer-btn.send {
    background: linear-gradient(135deg, #b45309, #f0a35c);
    color: #fff;
    box-shadow: 0 6px 16px rgba(240, 163, 92, 0.22);
}
.composer-btn.send:hover:not(:disabled) { background: linear-gradient(135deg, #c96712, #f6bd85); }
.composer-btn.send:disabled { background: #1c2840; color: var(--text-faint); cursor: not-allowed; box-shadow: none; }
.composer-btn.stop { background: #1c2840; color: var(--text); }
.composer-btn.stop:hover { background: #263352; }

/* Quiet two-sided status row: keyboard hints left, session status right. */
.composer-hint {
    max-width: var(--content-width);
    margin: 6px auto 0;
    padding: 0 4px;
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 6px 14px;
    flex-wrap: wrap;
    font-size: 0.75rem;
    color: var(--text-faint);
}

.composer-hint .hint-status {
    margin-left: auto;
    display: inline-flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 4px 10px;
    text-align: right;
}

/* Context-window meter: estimated next-send tokens vs the model's window. */
.context-meter {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.context-meter-bar {
    width: 72px;
    height: 6px;
    border-radius: 3px;
    background: var(--bg-elevated);
    border: 1px solid var(--border-soft);
    overflow: hidden;
    display: inline-block;
}

.context-meter-fill {
    display: block;
    height: 100%;
    background: linear-gradient(to right, var(--accent), var(--accent-bright));
    transition: width 0.4s ease;
}

.context-meter-fill.hot {
    background: linear-gradient(to right, var(--ember), var(--danger));
}

/* ---------- Auth / login ---------- */
.auth-shell {
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    background:
        radial-gradient(860px 520px at 50% -8%, rgba(37, 99, 235, 0.22), transparent 66%),
        radial-gradient(540px 360px at 76% 82%, rgba(240, 163, 92, 0.10), transparent 72%),
        var(--bg);
}

.login-card {
    width: 360px;
    max-width: 92vw;
    background: rgba(16, 26, 46, 0.88);
    border: 1px solid var(--border);
    border-radius: 16px;
    padding: 32px 28px;
    box-shadow:
        0 24px 70px rgba(1, 9, 22, 0.62),
        inset 0 1px 0 rgba(255, 255, 255, 0.035);
    backdrop-filter: blur(18px);
}

.login-logo {
    font-family: var(--serif);
    font-size: 1.9rem;
    font-weight: 600;
    text-align: center;
    color: var(--parchment);
}

.login-brand {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    margin-bottom: 4px;
}

.login-brand-icon {
    width: 76px;
    height: 76px;
    object-fit: contain;
    filter: drop-shadow(0 8px 18px rgba(37, 99, 235, 0.28));
}

.login-sub {
    text-align: center;
    color: var(--text-muted);
    margin: 6px 0 22px;
}

.login-form { display: flex; flex-direction: column; gap: 14px; }
.login-btn { margin-top: 6px; width: 100%; justify-content: center; }

.login-error {
    background: var(--danger-soft);
    color: var(--danger);
    border: 1px solid rgba(255, 107, 107, 0.3);
    border-radius: 8px;
    padding: 10px 12px;
    margin-bottom: 16px;
    font-size: 0.9rem;
}

.login-divider {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 16px 0 12px;
    color: var(--text-faint);
    font-size: 0.8rem;
}

.login-divider::before,
.login-divider::after {
    content: "";
    flex: 1;
    border-top: 1px solid var(--border);
}

.passkey-btn { width: 100%; }
#passkey-error { margin: 12px 0 0; }

.field { display: flex; flex-direction: column; gap: 6px; }
.field > span { font-size: 0.85rem; color: var(--text-muted); }

input, select, textarea, .input {
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    color: var(--text);
    border-radius: 9px;
    padding: 10px 12px;
    font-size: 0.95rem;
    font-family: inherit;
    outline: none;
}

input:focus, select:focus, textarea:focus, .input:focus { border-color: var(--accent); }

/* ---------- Buttons ---------- */
.btn, .btn-primary {
    border: 1px solid var(--border);
    background: var(--bg-elevated);
    color: var(--text);
    border-radius: 9px;
    padding: 9px 16px;
    font-size: 0.9rem;
    font-family: inherit;
    vertical-align: middle;
    cursor: pointer;
    transition: background 0.15s, border-color 0.15s, opacity 0.15s;
}

.btn:hover:not(:disabled), .btn-primary:hover:not(:disabled) { background: var(--surface-hover); }
.btn:disabled, .btn-primary:disabled { opacity: 0.5; cursor: not-allowed; }
.btn:focus-visible, .btn-primary:focus-visible { box-shadow: 0 0 0 3px var(--accent-soft); }
.btn.small { padding: 5px 12px; font-size: 0.82rem; }

.btn.primary, .btn-primary {
    background: var(--accent);
    border-color: var(--accent);
    color: #fff;
}

.btn.primary:hover:not(:disabled), .btn-primary:hover:not(:disabled) { background: var(--accent-hover); border-color: var(--accent-hover); }
.btn.danger { background: var(--danger-soft); border-color: rgba(255, 107, 107, 0.35); color: var(--danger); }
.btn.danger:hover:not(:disabled) { background: rgba(255, 107, 107, 0.2); }

.btn-link {
    background: none;
    border: none;
    color: var(--accent);
    cursor: pointer;
    font-size: 0.85rem;
    padding: 4px 6px;
}
.btn-link.danger { color: var(--danger); }

/* ---------- Admin ---------- */
.admin-page {
    max-width: 920px;
    margin: 0 auto;
    padding: 28px 24px 60px;
    overflow-y: auto;
    width: 100%;
}

.admin-header { margin-bottom: 20px; }
.admin-header h1 { margin: 0 0 4px; }
.admin-header p { margin: 0; }

.card {
    background: var(--card-bg);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 20px 22px;
    margin-bottom: 18px;
    box-shadow:
        0 18px 50px rgba(1, 9, 22, 0.20),
        inset 0 1px 0 rgba(255, 255, 255, 0.025);
}

.card h2 { margin: 0 0 6px; font-size: 1.1rem; }

.card-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 12px;
}

.card-head h2 { margin: 0; }
.card-actions { margin-top: 14px; display: flex; gap: 10px; }

.input.prompt, textarea.prompt { width: 100%; resize: vertical; line-height: 1.5; }
.input { width: 100%; }

.field-row {
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
}
.field-row .field { flex: 1; min-width: 220px; }

.banner {
    border-radius: 9px;
    padding: 11px 14px;
    margin-bottom: 16px;
    font-size: 0.9rem;
}
.banner.ok { background: var(--ok-soft); color: var(--ok); border: 1px solid rgba(78, 201, 143, 0.3); }
.banner.err { background: var(--danger-soft); color: var(--danger); border: 1px solid rgba(255, 107, 107, 0.3); }

.tag {
    display: inline-block;
    padding: 2px 9px;
    border-radius: 20px;
    font-size: 0.78rem;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    color: var(--text-muted);
}
.tag.ok { color: var(--ok); border-color: rgba(78, 201, 143, 0.4); }
.tag.warn { color: #e6b54a; border-color: rgba(230, 181, 74, 0.4); }

/* Grid table */
.grid { width: 100%; border-collapse: collapse; font-size: 0.9rem; }
.grid th {
    text-align: left;
    padding: 8px 10px;
    color: var(--text-muted);
    font-weight: 600;
    border-bottom: 1px solid var(--border);
    font-size: 0.82rem;
}
.grid td { padding: 10px; border-bottom: 1px solid var(--border-soft); vertical-align: middle; }
.grid code { font-size: 0.85em; color: var(--text-muted); }

/* Model rename (admin) */
.rename-btn { color: var(--text-faint); padding: 0 6px; font-size: 0.85em; }
.rename-btn:hover { color: var(--accent); }
.rename-editor { display: inline-flex; gap: 6px; align-items: center; }
.rename-editor .input { width: 200px; padding: 4px 8px; }

/* Usage analytics (admin) */
.grid th.num, .grid td.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.stat-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: 12px;
    margin-bottom: 20px;
}
.stat-tile {
    background: var(--card-bg);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 14px 18px;
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.stat-label { font-size: 0.8rem; color: var(--text-muted); }
.stat-value { font-size: 1.45rem; font-weight: 600; font-variant-numeric: tabular-nums; }
.meter-col { width: 140px; min-width: 100px; }
.meter {
    height: 6px;
    border-radius: 3px;
    background: var(--bg-elevated);
    overflow: hidden;
}
.meter-fill { height: 100%; border-radius: 3px; background: var(--accent); }
.expand-btn { color: var(--text-muted); padding: 0 4px; }
.sub-row td { color: var(--text-muted); border-bottom-style: dashed; }
.sub-row .num { font-size: 0.85rem; }
.model-id code { word-break: break-all; }

/* Toggle switch */
.switch { position: relative; display: inline-block; width: 38px; height: 22px; }
.switch input { opacity: 0; width: 0; height: 0; }
.slider {
    position: absolute;
    cursor: pointer;
    inset: 0;
    background: #263c52;
    border-radius: 22px;
    transition: 0.2s;
}
.slider::before {
    content: "";
    position: absolute;
    height: 16px;
    width: 16px;
    left: 3px;
    bottom: 3px;
    background: #fff;
    border-radius: 50%;
    transition: 0.2s;
}
.switch input:checked + .slider { background: var(--accent); }
.switch input:checked + .slider::before { transform: translateX(16px); }

/* Catalog */
.search { width: 100%; margin-bottom: 8px; }
.catalog { list-style: none; margin: 0; padding: 0; max-height: 480px; overflow-y: auto; }
.catalog li {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 6px;
    border-bottom: 1px solid var(--border-soft);
}
.catalog-info { flex: 1; min-width: 0; }
.catalog-name { font-size: 0.92rem; }
.catalog-id { font-size: 0.8rem; color: var(--text-muted); }
.catalog-meta { flex-shrink: 0; }

/* Scrollbars */
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-thumb { background: #1b2740; border-radius: 6px; border: 2px solid var(--bg); }
::-webkit-scrollbar-thumb:hover { background: #2a3a58; }
::-webkit-scrollbar-track { background: transparent; }

/* ---------- Blazor error UI ---------- */
#blazor-error-ui {
    color-scheme: light dark;
    background: #2a1215;
    color: #ffb4b4;
    bottom: 0;
    box-shadow: 0 -1px 4px rgba(0, 0, 0, 0.4);
    box-sizing: border-box;
    display: none;
    left: 0;
    padding: 0.9rem 1.4rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}

#blazor-error-ui .dismiss {
    cursor: pointer;
    position: absolute;
    right: 1rem;
    top: 0.75rem;
}

.blazor-error-boundary {
    background: #2a1215;
    padding: 1rem;
    color: #ffb4b4;
    border-radius: 8px;
}

.blazor-error-boundary::after {
    content: "An error has occurred.";
}

.loading-progress, .loading-progress-text { display: none; }

/* ---------- Mobile navigation drawer ---------- */
/* Hidden on desktop; the sidebar stays docked in the flex row. */
.drawer-toggle,
.drawer-backdrop { display: none; }

@media (max-width: 768px) {
    /* Sidebar becomes an off-canvas drawer, out of the flex flow so the
       content column gets the full viewport width. */
    .sidebar {
        position: fixed;
        top: 0;
        left: 0;
        z-index: 40;
        width: min(84vw, var(--sidebar-width));
        transform: translateX(-100%);
        transition: transform 0.22s ease;
        box-shadow: 0 0 40px rgba(0, 0, 0, 0.5);
    }
    .app-shell.drawer-open .sidebar { transform: translateX(0); }

    /* Dimming backdrop behind the open drawer. */
    .drawer-backdrop {
        display: block;
        position: fixed;
        inset: 0;
        z-index: 30;
        background: rgba(0, 0, 0, 0.5);
        opacity: 0;
        pointer-events: none;
        transition: opacity 0.22s ease;
    }
    .app-shell.drawer-open .drawer-backdrop { opacity: 1; pointer-events: auto; }

    /* Hamburger toggle, fixed at the top-left. Sits under the open drawer. */
    .drawer-toggle {
        display: flex;
        flex-direction: column;
        justify-content: center;
        gap: 4px;
        position: fixed;
        top: 9px;
        left: 10px;
        z-index: 25;
        width: 38px;
        height: 34px;
        padding: 0 8px;
        background: var(--bg-elevated);
        border: 1px solid var(--border);
        border-radius: 9px;
        cursor: pointer;
    }
    .drawer-toggle span {
        display: block;
        height: 2px;
        background: var(--text);
        border-radius: 2px;
    }

    /* Chat: clear the hamburger in the top bar, go edge-to-edge. */
    .chat-topbar { padding-left: 58px; }
    .messages { padding: 16px 12px; }
    .composer-wrap { padding: 10px 12px 14px; }

    /* Admin: clear the fixed hamburger and tighten padding. */
    .admin-page { padding: 60px 14px 48px; }
    .card { padding: 16px 14px; }
    .table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }

    /* Catalog rows stack their meta line on narrow screens. */
    .catalog li { flex-wrap: wrap; }
    .catalog-meta { flex-basis: 100%; }
}

/* ---- Multi-user admin: model grant checkboxes, selected row ---- */

.grant-list {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin: 10px 0;
}

.grant-item {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 10px;
    border: 1px solid var(--border-soft);
    border-radius: 8px;
    background: var(--bg-elevated);
    cursor: pointer;
}

.grant-item input[type="checkbox"] { accent-color: var(--accent); }

.grant-item code { margin-left: 6px; }

tr.row-selected td { background: var(--accent-soft); }

/* ---- Thinking (reasoning) ---- */

.reasoning-config-row td { background: var(--bg-elevated); }

.reasoning-config {
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 10px 6px;
}

.thinking {
    margin: 0 0 10px;
    border: 1px solid var(--border-soft);
    border-radius: 10px;
    background: var(--bg-elevated);
}

.thinking summary {
    cursor: pointer;
    padding: 8px 12px;
    color: var(--text-muted);
    font-size: 0.85rem;
    user-select: none;
}

.thinking[open] summary { border-bottom: 1px solid var(--border-soft); }

.thinking-text {
    padding: 10px 12px;
    color: var(--text-faint);
    font-size: 0.85rem;
    line-height: 1.5;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    max-height: 320px;
    overflow-y: auto;
}

/* ---- Attachments ---- */

.composer-btn.attach {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    font-size: 1.05rem;
}

.pending-files {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-bottom: 8px;
}

.pending-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    max-width: 260px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    padding: 4px 8px;
    border: 1px solid var(--border-soft);
    border-radius: 999px;
    background: var(--bg-elevated);
    font-size: 0.8rem;
    color: var(--text-muted);
}

.pending-remove {
    border: none;
    background: none;
    color: var(--text-faint);
    cursor: pointer;
    font-size: 0.95rem;
    padding: 0 2px;
}

.pending-remove:hover { color: var(--text); }

.composer-file-error {
    margin-bottom: 8px;
    font-size: 0.8rem;
    color: #e5484d;
}

.attachments {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 8px;
}

.attach-thumb {
    max-width: 280px;
    max-height: 220px;
    border-radius: 10px;
    border: 1px solid var(--border-soft);
    display: block;
}

.attach-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 10px;
    border: 1px solid var(--border-soft);
    border-radius: 8px;
    background: var(--bg-elevated);
    color: var(--text);
    text-decoration: none;
    font-size: 0.85rem;
    max-width: 320px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.attach-chip:hover { border-color: var(--accent); }

/* ---- Image-generation tool ---- */

.tool-status {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    color: var(--text-muted);
    font-size: 0.9rem;
    padding: 4px 0;
    animation: pulse 1.4s ease-in-out infinite;
}

@keyframes pulse {
    0%, 100% { opacity: 0.55; }
    50% { opacity: 1; }
}

.msg-tool .attach-thumb {
    max-width: 420px;
    max-height: 420px;
}

/* ---- iOS standalone (Add to Home Screen): keep content out of the notch and
   home-indicator areas. Insets are 0 everywhere else. ---- */

@supports (padding: env(safe-area-inset-top)) {
    /* The fixed hamburger must drop below the status bar / Dynamic Island —
       at its normal 9px it sits level with the island and can't be tapped.
       Scoped to the drawer breakpoint so desktop padding stays untouched. */
    @media (max-width: 768px) {
        .drawer-toggle {
            top: calc(9px + env(safe-area-inset-top));
            left: calc(10px + env(safe-area-inset-left));
        }

        /* Admin pages clear the (now lower) fixed hamburger. */
        .admin-page {
            padding-top: calc(60px + env(safe-area-inset-top));
        }
    }

    .chat-topbar {
        height: auto;
        min-height: 52px;
        padding-top: env(safe-area-inset-top);
    }

    .sidebar {
        padding-top: env(safe-area-inset-top);
        padding-left: env(safe-area-inset-left);
    }

    .composer-wrap {
        padding-bottom: calc(18px + env(safe-area-inset-bottom));
    }

    .sidebar-footer {
        padding-bottom: calc(8px + env(safe-area-inset-bottom));
    }
}

/* Mobile browsers overshoot 100vh by the height of the retracted URL bar,
   burying the composer behind browser chrome; dynamic viewport units track
   the truly visible height. Scoped to the drawer breakpoint so desktop keeps
   the classic 100vh unchanged. */
@supports (height: 100dvh) {
    @media (max-width: 768px) {
        .app-shell, .sidebar, .chat { height: 100dvh; }
        .auth-shell { min-height: 100dvh; }
    }
}

/* ============================= RPG mode ============================= */

/* Sidebar: the adventure button sits under "New chat" with a warmer accent. */
.new-adventure-btn {
    background: var(--ember-soft);
    border-color: rgba(240, 163, 92, 0.45);
}
.new-adventure-btn:hover { background: rgba(240, 163, 92, 0.24); }

/* Topbar: campaign chips replace the model pickers. */
.rpg-topbar {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
}
.rpg-topbar::-webkit-scrollbar { display: none; }

.rpg-chip {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 4px 12px;
    border-radius: 999px;
    border: 1px solid var(--border);
    background: var(--bg-elevated);
    color: var(--text-muted);
    font-size: 0.82rem;
    white-space: nowrap;
}
.rpg-chip.genre {
    color: var(--parchment);
    border-color: rgba(240, 163, 92, 0.35);
    background: rgba(14, 22, 38, 0.7);
}
.rpg-chip.phase { color: var(--ember-bright); border-color: rgba(240, 163, 92, 0.4); }
.rpg-chip.god {
    color: #ffd166;
    border-color: rgba(255, 209, 102, 0.45);
    background: rgba(255, 209, 102, 0.1);
}
.rpg-chip.toggle { cursor: pointer; }
.rpg-chip.toggle:hover { background: var(--surface-hover); color: var(--text); }

/* Party & journal panel: floats over the messages, below the topbar. */
.rpg-panel {
    position: absolute;
    top: 52px;
    right: 0;
    bottom: 0;
    width: min(360px, 92vw);
    background: var(--sidebar-bg);
    border-left: 1px solid var(--border);
    overflow-y: auto;
    padding: 14px 16px 24px;
    z-index: 30;
    box-shadow: -12px 0 30px rgba(0, 0, 0, 0.35);
}
.chat { position: relative; }

.rpg-panel-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin-bottom: 10px;
}
.rpg-panel-head h3 { margin: 0; font-size: 1.05rem; }
.rpg-panel-close {
    background: none;
    border: none;
    color: var(--text-muted);
    font-size: 1.3rem;
    cursor: pointer;
    line-height: 1;
    padding: 2px 6px;
}
.rpg-panel-close:hover { color: var(--text); }

.rpg-section { margin-bottom: 18px; }
.rpg-section h4 {
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-faint);
    margin-bottom: 8px;
}

.char-card {
    border: 1px solid var(--border-soft);
    border-radius: var(--radius);
    background: var(--card-bg);
    padding: 8px 10px;
    margin-bottom: 8px;
}
.char-card summary {
    display: flex;
    align-items: center;
    gap: 10px;
    cursor: pointer;
    list-style: none;
    min-width: 0;
}
.char-card summary::-webkit-details-marker { display: none; }
.char-card.char-gone { opacity: 0.6; }

.char-avatar {
    width: 42px;
    height: 42px;
    border-radius: 50%;
    object-fit: cover;
    border: 1px solid var(--border);
    flex-shrink: 0;
}
.char-avatar-fallback {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 1.2rem;
    background: var(--bg-elevated);
}
.char-name {
    font-weight: 600;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.char-tags { margin-left: auto; display: flex; gap: 4px; flex-shrink: 0; }

.rpg-tag {
    font-size: 0.7rem;
    padding: 2px 8px;
    border-radius: 999px;
    border: 1px solid var(--border);
    color: var(--text-faint);
    white-space: nowrap;
}
.rpg-tag.status-dead { color: var(--danger); border-color: rgba(255, 107, 107, 0.4); }
.rpg-tag.status-retired { color: #e6b54a; border-color: rgba(230, 181, 74, 0.4); }

.char-visual { margin: 8px 2px 4px; color: var(--text-muted); font-style: italic; }
.char-sheet {
    margin: 6px 0 2px;
    padding: 8px 10px;
    background: var(--bg);
    border-radius: 8px;
    font-size: 0.75rem;
    overflow-x: auto;
    white-space: pre-wrap;
    word-break: break-word;
    color: var(--text-muted);
}

.journal-entry {
    border-bottom: 1px dashed var(--border-soft);
    padding: 6px 2px;
}
.journal-entry summary { cursor: pointer; font-size: 0.88rem; }
.journal-entry p { margin: 6px 0 4px; color: var(--text-muted); }

/* Choice buttons: the GM's options for the next turn, above the composer. */
.rpg-choices {
    max-width: var(--content-width);
    margin: 0 auto 10px;
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.rpg-choice {
    text-align: left;
    padding: 10px 16px;
    border-radius: var(--radius);
    border: 1px solid var(--border);
    background: var(--bg-elevated);
    color: var(--text);
    font-size: 0.92rem;
    cursor: pointer;
    transition: border-color 0.12s ease, background 0.12s ease, transform 0.06s ease;
}
.rpg-choice::before { content: "› "; color: var(--ember); font-weight: 700; }
.rpg-choice:hover:not(:disabled) {
    border-color: var(--accent);
    background: var(--accent-soft);
    transform: translateX(2px);
}
.rpg-choice:disabled { opacity: 0.5; cursor: not-allowed; }

/* Dice results render as visible proof of fair rolls. */
.dice-roll {
    display: inline-block;
    padding: 8px 14px;
    border-radius: var(--radius);
    border: 1px solid rgba(255, 209, 102, 0.35);
    background: rgba(255, 209, 102, 0.08);
    color: #ffd166;
    font-size: 0.92rem;
    font-variant-numeric: tabular-nums;
}

/* New-adventure setup page. */
.adventure-setup .genre-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-bottom: 12px;
}

/* Selectable pill chips (genre presets). */
.chip {
    padding: 4px 12px;
    border-radius: 20px;
    border: 1px solid var(--border);
    background: var(--bg-elevated);
    color: var(--text-muted);
    font-size: 0.85rem;
    cursor: pointer;
    transition: background 0.15s, border-color 0.15s, color 0.15s;
    white-space: nowrap;
}

.chip:hover:not(:disabled) { background: var(--surface-hover); color: var(--text); }
.chip.active { background: var(--ember-soft); border-color: var(--ember); color: var(--text); }
.chip:disabled { opacity: 0.5; cursor: not-allowed; }
.btn.big { padding: 12px 26px; font-size: 1rem; }

/* (≤768px: .rpg-panel goes full-screen — see the mobile drawer block.) */

/* ===================== RPG mode: Phase 2/3 additions ===================== */

/* Living scene backdrop: sits behind the message stream, dimmed under a
   gradient so the prose stays readable; fades in when it changes. */
.rpg-backdrop {
    position: absolute;
    top: 52px;
    left: 0;
    right: 0;
    bottom: 0;
    background-size: cover;
    background-position: center;
    opacity: 0;
    animation: backdrop-in 1.2s ease forwards;
    pointer-events: none;
    z-index: 0;
}
.rpg-backdrop::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(to bottom,
        rgba(7, 13, 24, 0.82) 0%,
        rgba(7, 13, 24, 0.62) 40%,
        rgba(7, 13, 24, 0.88) 100%);
}
@keyframes backdrop-in {
    to { opacity: 1; }
}
.messages, .composer-wrap { position: relative; z-index: 1; }

.rpg-chip.scene {
    color: var(--text);
    max-width: 220px;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Cover art banner at the top of the party panel. */
.rpg-cover {
    width: calc(100% + 32px);
    margin: -14px -16px 10px;
    max-height: 150px;
    object-fit: cover;
    border-bottom: 1px solid var(--border);
}

/* Relationship meters. */
.rel-meters { margin: 8px 2px 4px; display: flex; flex-direction: column; gap: 4px; }
.rel-row { display: flex; align-items: center; gap: 8px; }
.rel-label {
    width: 52px;
    flex-shrink: 0;
    font-size: 0.72rem;
    text-transform: capitalize;
    color: var(--text-faint);
}
.rel-bar {
    flex: 1;
    height: 6px;
    border-radius: 999px;
    background: var(--bg);
    overflow: hidden;
}
.rel-fill {
    height: 100%;
    border-radius: 999px;
    background: linear-gradient(to right, var(--accent), var(--accent-bright));
    transition: width 0.4s ease;
}
.rel-value {
    width: 24px;
    text-align: right;
    font-size: 0.72rem;
    color: var(--text-faint);
    font-variant-numeric: tabular-nums;
}

/* Gallery grid. */
.gallery-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 6px;
}
.gallery-grid img {
    width: 100%;
    aspect-ratio: 1;
    object-fit: cover;
    border-radius: 8px;
    border: 1px solid var(--border-soft);
    transition: border-color 0.12s ease;
}
.gallery-grid a:hover img { border-color: var(--accent); }

/* Panel settings & charter. */
.rpg-setting { margin: 8px 0; }
.rpg-setting > span { font-size: 0.78rem; color: var(--text-faint); }
.charter-editor { width: 100%; margin: 4px 0 8px; font-size: 0.85rem; }
.rpg-panel-actions { display: flex; gap: 8px; flex-wrap: wrap; }

/* "Previously on…" recap overlay. */
.rpg-recap-overlay {
    position: absolute;
    inset: 0;
    background: rgba(4, 10, 18, 0.72);
    backdrop-filter: blur(3px);
    z-index: 40;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
}
.rpg-recap {
    max-width: 560px;
    max-height: 80%;
    overflow-y: auto;
    background: var(--card-bg);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 24px 28px;
    box-shadow: 0 18px 60px rgba(0, 0, 0, 0.55);
}
.rpg-recap h3 { margin-bottom: 14px; font-size: 1.2rem; font-family: var(--serif); color: var(--parchment); }
.rpg-recap h4 { font-size: 1rem; margin: 12px 0 4px; font-family: var(--serif); color: var(--ember-bright); }
.rpg-recap p { color: var(--text-muted); font-size: 0.92rem; margin-bottom: 8px; }
.rpg-recap-scene { font-style: italic; }
.rpg-recap .btn { margin-top: 10px; }

/* GM thinking selector, styled as a topbar chip. */
select.rpg-thinking {
    appearance: none;
    -webkit-appearance: none;
    cursor: pointer;
    max-width: 190px;
    overflow: hidden;
    text-overflow: ellipsis;
}
select.rpg-thinking:hover:not(:disabled) { background: var(--surface-hover); color: var(--text); }
select.rpg-thinking:disabled { opacity: 0.5; cursor: not-allowed; }

/* ---- Character mode ----------------------------------------------------- */

/* Library gender split: a segmented switch above the grid. */
.char-tabs {
    display: flex;
    gap: 4px;
    margin: 12px 0 4px;
    padding: 4px;
    background: var(--bg-elevated);
    border: 1px solid var(--border-soft);
    border-radius: 10px;
    width: fit-content;
    max-width: 100%;
    flex-wrap: wrap;
}

.char-tab {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 14px;
    border: none;
    border-radius: 7px;
    background: transparent;
    color: var(--text-muted, var(--text));
    font-size: 0.9rem;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.15s, color 0.15s;
}

.char-tab:hover { color: var(--text); background: var(--card-bg); }

.char-tab.active {
    background: var(--accent);
    color: #fff;
}

.char-tab-count {
    font-size: 0.78rem;
    font-weight: 600;
    opacity: 0.75;
    padding: 0 5px;
    border-radius: 999px;
    background: rgba(0, 0, 0, 0.22);
}

.char-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
    gap: 14px;
    margin: 8px 0;
}

.char-tile {
    background: var(--bg-elevated);
    border: 1px solid var(--border-soft);
    border-radius: var(--radius);
    padding: 12px;
    display: flex;
    flex-direction: column;
    gap: 6px;
    transition: border-color 0.15s;
}

.char-tile.selected { border-color: var(--accent); }

.char-tile-portrait {
    position: relative;
    display: block;
    width: 100%;
    aspect-ratio: 1;
    border-radius: 10px;
    overflow: hidden;
    background: var(--card-bg);
}

/* Natural aspect ratio, positioned by the stored profile crop (width = zoom %,
   focus-aligned on both axes) — the same formula the cropper applies live, so
   the tile is a truthful preview of what was framed. */
.char-tile-portrait img {
    position: absolute;
    height: auto;
    max-width: none;
    display: block;
}

/* Selection hit area: the whole portrait, minus the controls layered over it. */
.char-tile-hit {
    position: absolute;
    inset: 0;
    border: none;
    padding: 0;
    background: transparent;
    cursor: pointer;
}

.char-tile-crop {
    position: absolute;
    bottom: 6px;
    right: 6px;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    padding: 0;
    border: none;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.55);
    color: #fff;
    cursor: pointer;
    opacity: 0;
    transition: opacity 0.15s, background 0.15s;
}

.char-tile:hover .char-tile-crop,
.char-tile-crop:focus-visible { opacity: 1; }
.char-tile-crop:hover { background: var(--accent); }

/* Touch has no hover to reveal it: show it outright, at a thumb-sized target. */
@media (hover: none) {
    .char-tile-crop { opacity: 1; width: 32px; height: 32px; }
}

/* WYSIWYG profile crop, in place on the tile. */
.char-tile-portrait.cropping {
    cursor: grab;
    touch-action: none;
    outline: 2px dashed var(--accent);
    outline-offset: -2px;
}
.char-tile-portrait.cropping:active { cursor: grabbing; }
.char-tile-portrait.cropping img { pointer-events: none; user-select: none; }

.char-tile-fallback {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 3rem;
}

.char-tile-check {
    position: absolute;
    top: 8px;
    right: 8px;
    background: var(--accent);
    color: #fff;
    border-radius: 50%;
    width: 26px;
    height: 26px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 700;
}

.char-tile-name { font-weight: 600; }

.char-tile-desc {
    flex: 1;
    overflow: hidden;
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
}

.char-tile-actions { display: flex; gap: 6px; }

.char-image-row {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin: 8px 0;
}

/* Image row + the sidebar-shaped live preview side by side. */
.char-image-editor {
    display: flex;
    gap: 18px;
    align-items: flex-start;
    flex-wrap: wrap;
}

.char-pane-preview {
    display: flex;
    flex-direction: column;
    gap: 6px;
    align-items: center;
}

/* The portrait framing editor: mirrors .cast-portrait-frame proportions (the
   live pane runs ~311×600) and uses the SAME height-fill rendering, so what
   is framed here is what every chat shows — on every screen size, because the
   framing is stored relative to the image, not to any pane. */
.char-pane-preview-frame {
    width: 232px;
    height: 448px;
    border-radius: 12px;
    border: 1px solid var(--border);
    background: rgba(0, 0, 0, 0.2);
    overflow: hidden;
    position: relative;
    flex: 0 0 auto;
}

.char-pane-preview-frame img {
    position: absolute;
    width: auto;
    height: auto;
    max-width: none;
    max-height: none;
    display: block;
}

.char-pane-preview-frame.cropping {
    cursor: grab;
    touch-action: none;
    outline: 2px dashed var(--accent);
    outline-offset: -2px;
}
.char-pane-preview-frame.cropping:active { cursor: grabbing; }
.char-pane-preview-frame.cropping img { pointer-events: none; user-select: none; }

.char-pane-preview-caption {
    text-align: center;
    max-width: 232px;
}

.char-pane-preview-actions {
    display: flex;
    gap: 6px;
    flex-wrap: wrap;
    justify-content: center;
}

/* Reference thumbs double as the framing target picker. */
.char-image-editor .char-image-thumb { cursor: pointer; }

.char-image-editor .char-image-thumb.framing {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/* Per-look framing button, mirrored from the delete × on the other corner. */
.look-frame-btn {
    position: absolute;
    bottom: 2px;
    left: 2px;
    width: 22px;
    height: 22px;
    border: none;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.65);
    color: #fff;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
}

.look-frame-btn:hover { background: var(--accent); }

.char-image-cell {
    display: flex;
    flex-direction: column;
    gap: 4px;
    width: 96px;
}

.char-focus-slider {
    width: 100%;
    margin: 0;
    accent-color: var(--accent, #7aa2f7);
    cursor: pointer;
}

/* ---- Thread settings (retroactive story / persona) ---- */

.thread-settings-menu {
    min-width: 320px;
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 12px;
}

    .thread-settings-menu .field span {
        font-size: 0.8em;
    }

/* ---- Voice (TTS) ---- */

.tts-controls {
    display: inline-flex;
    align-items: center;
    gap: 8px;
}

.tts-autoplay {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    cursor: pointer;
    user-select: none;
}

    .tts-autoplay input {
        accent-color: var(--accent, #7aa2f7);
        margin: 0;
    }

.tts-error {
    color: var(--danger, #f7768e);
}

.msg-action.tts-live {
    color: var(--accent, #7aa2f7);
}

.composer-btn.mic.recording {
    animation: mic-pulse 1.2s ease-in-out infinite;
}

@keyframes mic-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.45; }
}

.char-voice-row {
    display: flex;
    gap: 8px;
    align-items: center;
}

    .char-voice-row select {
        flex: 1;
    }

.char-image-thumb {
    position: relative;
    width: 96px;
    height: 96px;
    border-radius: 10px;
    overflow: hidden;
    border: 1px solid var(--border-soft);
}

.char-image-thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/* The active reference: the portrait everywhere and the base image every
   generated look starts from — ember ring so it reads at a glance. */
.char-image-thumb.active {
    border-color: var(--ember);
    box-shadow: 0 0 0 2px var(--ember-soft);
}

.char-image-remove {
    position: absolute;
    top: 4px;
    right: 4px;
    width: 22px;
    height: 22px;
    border: none;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.65);
    color: #fff;
    cursor: pointer;
    line-height: 1;
}

.char-image-remove:hover { background: var(--danger); }

.char-image-add {
    width: 96px;
    height: 96px;
    border: 1px dashed var(--border);
    border-radius: 10px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 2rem;
    color: var(--text-faint);
    cursor: pointer;
}

.char-image-add:hover { border-color: var(--accent); color: var(--accent); }

/* Cast bar in the chat topbar */
.cast-bar {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px;
}

.cast-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: var(--bg-elevated);
    border: 1px solid var(--border-soft);
    border-radius: 999px;
    padding: 3px 10px 3px 4px;
    font-size: 0.85rem;
}

/* Avatar-shaped surfaces are frames, not bare imgs: the profile crop zooms the
   image inside a fixed circle, which needs something to clip against. */
.avatar-frame {
    position: relative;
    overflow: hidden;
    flex-shrink: 0;
}

.avatar-frame img {
    position: absolute;
    height: auto;
    max-width: none;
    display: block;
}

.cast-chip-avatar {
    width: 24px;
    height: 24px;
    border-radius: 50%;
    object-fit: cover;
    display: block;
}

.cast-chip-fallback {
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.85rem;
}

.cast-chip-name { white-space: nowrap; }

.cast-chip-remove {
    border: none;
    background: none;
    color: var(--text-faint);
    cursor: pointer;
    padding: 0 2px;
    font-size: 1rem;
    line-height: 1;
}

.cast-chip-remove:hover:not(:disabled) { color: var(--danger); }

.cast-add { position: relative; }

.cast-add-menu {
    position: absolute;
    top: calc(100% + 6px);
    left: 0;
    z-index: 30;
    background: var(--card-bg);
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 8px;
    min-width: 200px;
    display: flex;
    flex-direction: column;
    gap: 4px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45);
}

.cast-add-option {
    border: none;
    background: none;
    color: var(--text);
    text-align: left;
    padding: 6px 8px;
    border-radius: 6px;
    cursor: pointer;
}

.cast-add-option:hover:not(:disabled) { background: var(--accent-soft); }

/* Stage directions (joins/leaves) as ruled, book-style notes in the stream */
.cast-note {
    display: flex;
    align-items: center;
    gap: 14px;
    text-align: center;
    color: var(--text-faint);
    font-family: var(--serif);
    font-style: italic;
    font-size: 0.9rem;
    margin: 14px 0;
}

.cast-note::before,
.cast-note::after {
    content: "";
    flex: 1;
    height: 1px;
    background: linear-gradient(90deg, transparent, var(--border));
}

.cast-note::after { background: linear-gradient(90deg, var(--border), transparent); }

/* update_world results: the AI wrote new canon into the story world. */
.cast-note.world-note {
    color: var(--accent, #7aa2f7);
    opacity: 0.85;
}

/* Chapter boundaries: a labeled rule after the last message a storybook
   chapter covers, so it is obvious where one chapter ends and the next
   begins while reading back. */
.chapter-divider {
    display: flex;
    align-items: center;
    gap: 14px;
    text-align: center;
    color: var(--accent, #7aa2f7);
    font-family: var(--serif);
    font-size: 0.82rem;
    letter-spacing: 0.04em;
    margin: 22px 0;
    opacity: 0.9;
}

.chapter-divider::before,
.chapter-divider::after {
    content: "";
    flex: 1;
    height: 1px;
    background: linear-gradient(90deg, transparent, var(--accent, #7aa2f7));
    opacity: 0.45;
}

.chapter-divider::after { background: linear-gradient(90deg, var(--accent, #7aa2f7), transparent); }

.chapter-divider span {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    max-width: 70%;
}

/* Boundary nudge: quiet until the divider is hovered, then two chevrons that
   pull/push the chapter's end one message at a time. */
.chapter-boundary-btn {
    display: inline-flex;
    align-items: center;
    padding: 1px 4px;
    border: 1px solid transparent;
    border-radius: 6px;
    background: none;
    color: inherit;
    cursor: pointer;
    opacity: 0;
    transition: opacity 0.15s ease, border-color 0.15s ease;
}

.chapter-divider:hover .chapter-boundary-btn,
.chapter-boundary-btn:focus-visible {
    opacity: 0.75;
}

.chapter-boundary-btn:hover:not(:disabled) {
    opacity: 1;
    border-color: var(--accent, #7aa2f7);
}

.chapter-boundary-btn:disabled { cursor: default; opacity: 0.25; }

/* Message paging: the earlier-messages indicator at the top of the list. */
.load-older-hint {
    display: flex;
    justify-content: center;
    padding: 6px 0 10px;
    color: var(--text-faint);
}

/* Character mode: the "record a chapter?" consent nudge above the composer. */
.chapter-nudge {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    flex-wrap: wrap;
    max-width: var(--content-width);
    margin: 0 auto 8px;
    padding: 8px 12px;
    border: 1px solid var(--border);
    border-radius: 10px;
    background: var(--sidebar-bg);
    font-size: 0.85rem;
    color: var(--text-muted);
}

/* Assistant panels: the retry escape hatch above the composer. */
.world-chat-retry {
    display: flex;
    justify-content: center;
    margin: 2px 0 6px;
}

/* ---- Character mode: large portrait pane ---- */

.cast-portrait-pane {
    position: absolute;
    top: 52px;
    right: 0;
    bottom: 0;
    width: min(340px, 92vw);
    background: var(--sidebar-bg);
    border-left: 1px solid var(--border);
    overflow-y: auto;
    padding: 12px 14px 20px;
    z-index: 25;
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.cast-portrait-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.cast-portrait-head h3 { margin: 0; font-size: 1rem; }

/* The big portrait: a frame that absorbs all pane height not used by the
   header/nav/strip. The image inside always fills the frame's full height
   (its framing, set on the Characters page, is stored relative to the image,
   so it looks the same on every screen size); when the height-filled image
   is wider than the frame the sides crop at the stored horizontal focus. */
.cast-portrait-frame {
    flex: 1;
    min-height: 240px;
    border-radius: 12px;
    border: 1px solid var(--border);
    background: rgba(0, 0, 0, 0.2);
    overflow: hidden;
    position: relative;
}

/* Natural aspect ratio — sizing/positioning comes from the inline style
   (height = zoom %, width follows, focus-aligned on both axes). */
.cast-portrait-frame img {
    position: absolute;
    width: auto;
    height: auto;
    max-width: none;
    max-height: none;
    display: block;
}

.cast-portrait-nav {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 12px;
}

.cast-portrait-fallback {
    font-size: 4rem;
    text-align: center;
    padding: 48px 0 12px;
    opacity: 0.45;
}

.cast-portrait-strip {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 2px;
}

.cast-portrait-thumb {
    position: relative;
    width: 48px;
    height: 48px;
    border-radius: 10px;
    overflow: hidden;
    padding: 0;
    border: 2px solid transparent;
    background: var(--border);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.3rem;
}

.cast-portrait-thumb img {
    position: absolute;
    height: auto;
    max-width: none;
    display: block;
}

.cast-portrait-thumb.focused { border-color: var(--accent, #7aa2f7); }

/* On wide screens the pane sits BESIDE the conversation: the message stream and
   composer shift left to make room. Below that, it overlays like the RPG panel. */
@media (min-width: 1100px) {
    .chat.portrait-open .messages,
    .chat.portrait-open .composer-wrap {
        padding-right: 356px;
    }
    .cast-portrait-pane { box-shadow: none; }
}

@media (max-width: 1099px) {
    .cast-portrait-pane { box-shadow: -12px 0 30px rgba(0, 0, 0, 0.35); }
}

/* (≤768px: .cast-portrait-pane goes full-screen — see the mobile drawer block.) */

.cast-msg-avatar {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    object-fit: cover;
    display: block;
}

.storybook-summary { white-space: pre-wrap; }

/* ---- Stories ------------------------------------------------------------ */

.story-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 10px 0;
    border-bottom: 1px solid var(--border-soft);
}

.story-row:last-child { border-bottom: none; }

.story-row-name { font-weight: 600; }

.world-count {
    font-size: 0.8rem;
    color: var(--text-faint);
    margin: -6px 0 10px;
    text-align: right;
}

.world-count.high { color: #e6b54a; }
.world-count.over { color: var(--danger); }

.world-count-total {
    font-size: 0.85rem;
    color: var(--text-muted);
    background: var(--accent-soft);
    border-radius: 8px;
    padding: 8px 12px;
}

.launch-story-row {
    display: flex;
    align-items: flex-end;
    gap: 10px;
    flex-wrap: wrap;
    margin-bottom: 4px;
}

.launch-story-field { min-width: 240px; }

.storybook-group {
    margin: 20px 0 10px;
    font-size: 1.1rem;
    color: var(--text-muted);
}

/* World-building assistant panel */
.world-chat-log {
    max-height: 420px;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 4px 0 10px;
}

.world-chat-msg { display: flex; flex-direction: column; gap: 2px; }

.world-chat-who {
    font-size: 0.75rem;
    color: var(--text-faint);
}

.world-chat-text {
    white-space: pre-wrap;
    background: var(--bg-elevated);
    border: 1px solid var(--border-soft);
    border-radius: 10px;
    padding: 8px 12px;
}

.world-chat-user .world-chat-text {
    background: var(--user-bubble);
    align-self: flex-start;
}

/* ---- QoL batch: reply-as targeting, lore editor --------------------------- */

.cast-chip-name-btn {
    border: none;
    background: none;
    color: var(--text);
    cursor: pointer;
    padding: 0;
    font-size: 0.85rem;
    white-space: nowrap;
}

.cast-chip-name-btn:disabled { cursor: default; }

.cast-chip.targeted {
    border-color: var(--accent);
    background: var(--accent-soft);
}

.cast-chip-target { font-size: 0.8rem; }

.lore-editor {
    background: var(--bg-elevated);
    border: 1px solid var(--border-soft);
    border-radius: 10px;
    padding: 12px;
    margin: 10px 0;
}

/* Character editor: the collapsible card-extras section and its lorebook. */
.card-extras {
    border: 1px solid var(--border-soft);
    border-radius: 10px;
    padding: 12px;
    margin-top: 8px;
}

.lore-row {
    border: 1px solid var(--border-soft);
    border-radius: 8px;
    padding: 6px 10px;
    margin: 6px 0;
}

.lore-row.editing { border-color: var(--accent); }

.lore-row-head {
    display: flex;
    align-items: center;
    gap: 8px;
}

.lore-row-head strong { flex: 0 0 auto; }

.lore-row-head .muted {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Character editor: the private-journal viewer. */
.journal-entry {
    border: 1px solid var(--border-soft);
    border-radius: 8px;
    padding: 8px 12px;
    margin: 8px 0;
}

.journal-entry-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}

.journal-entry-text {
    margin: 6px 0 0;
    font-style: italic;
    white-space: pre-wrap;
}

/* Reply takes: the n/N counter between the swipe chevrons. */
.take-counter {
    align-self: center;
    font-size: 0.78rem;
    color: var(--text-muted, var(--muted));
    padding: 0 2px;
    white-space: nowrap;
}

/* Expression variants: emotion caption on the editor grid + pane mood tag. */
.expression-thumb { position: relative; }

.expression-caption {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    font-size: 0.62rem;
    text-align: center;
    text-transform: capitalize;
    background: rgba(0, 0, 0, 0.55);
    color: #fff;
    padding: 1px 2px;
    pointer-events: none;
}

.portrait-mood {
    margin-left: 8px;
    font-weight: 400;
    text-transform: capitalize;
}

/* ---- Search page ---------------------------------------------------------- */

.search-hit {
    border-bottom: 1px solid var(--border-soft);
    padding: 8px 0;
}

.search-hit:last-child { border-bottom: none; }

.search-hit-head {
    display: flex;
    align-items: baseline;
    gap: 8px;
}

.search-hit-kind {
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-muted, var(--muted));
    border: 1px solid var(--border-soft);
    border-radius: 999px;
    padding: 1px 8px;
    white-space: nowrap;
}

.search-hit-title {
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.search-hit-snippet {
    margin: 4px 0 0;
    font-size: 0.88rem;
}

/* ---- Local roleplay aids: reply suggestions, ledger ----------------------- */

/* 💡 suggestions reuse the RPG-choice look; the dismiss stays small. */
.reply-suggestions .rpg-choice.suggestion-dismiss {
    align-self: flex-end;
    padding: 4px 12px;
    font-size: 0.8rem;
}
.reply-suggestions .rpg-choice.suggestion-dismiss::before { content: ""; }

/* The ⚙ menu's scene-ledger whiteboard. */
.scene-ledger-editor {
    font-family: var(--mono, ui-monospace, monospace);
    font-size: 0.8rem;
    min-width: 320px;
    resize: vertical;
}

/* ---- Scene portraits: the looks gallery in the portrait pane -------------- */

.paint-toggle input { vertical-align: middle; }

.scene-looks {
    padding: 8px 10px;
    border-top: 1px solid var(--border-soft, var(--border));
}

.scene-looks-strip {
    display: flex;
    gap: 6px;
    overflow-x: auto;
    padding-bottom: 4px;
}

.scene-look-thumb {
    flex: 0 0 auto;
    width: 52px;
    height: 68px;
    padding: 0;
    border-radius: 8px;
    border: 2px solid var(--border);
    background: var(--bg-elevated);
    overflow: hidden;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.2rem;
}

.scene-look-thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.scene-look-thumb:hover { border-color: var(--accent); }

.scene-look-thumb.current {
    border-color: var(--accent-bright, var(--accent));
    box-shadow: 0 0 0 1px var(--accent-soft);
}

/* Two-tier portrait control + explicit-look badge */
.paint-mode {
    background: var(--bg-elevated);
    color: var(--text);
    border: 1px solid var(--border);
    border-radius: 6px;
    font-size: 0.78rem;
    padding: 1px 4px;
}

.scene-look-thumb { position: relative; }

.look-explicit-badge {
    position: absolute;
    bottom: 2px;
    right: 2px;
    font-size: 0.6rem;
    line-height: 1;
    background: rgba(0, 0, 0, 0.55);
    border-radius: 4px;
    padding: 1px 2px;
}

/* Reference-upscale review: original vs candidate, side by side */
.upscale-review {
    border: 1px solid var(--border-soft, var(--border));
    border-radius: 10px;
    padding: 12px;
    margin-top: 10px;
}

.upscale-compare {
    display: flex;
    gap: 12px;
    margin: 8px 0;
}

.upscale-compare figure {
    flex: 1;
    margin: 0;
    text-align: center;
}

.upscale-compare img {
    max-width: 100%;
    max-height: 360px;
    object-fit: contain;
    border-radius: 8px;
    border: 1px solid var(--border);
}

/* ================= Lantern story mode (character & RPG threads) ================= */

/* The topbar becomes a softly lit scene band over the midnight canvas. */
.chat.character .chat-topbar,
.chat.rpg .chat-topbar {
    background:
        radial-gradient(420px 130px at 16% 0%, rgba(240, 163, 92, 0.10), transparent 70%),
        radial-gradient(560px 200px at 88% -40%, rgba(37, 99, 235, 0.18), transparent 65%),
        var(--bg);
}

/* Narrative prose reads like a book: serif, a touch larger, looser leading. */
.chat.character .markdown,
.chat.rpg .markdown,
.chat.character .user-text,
.chat.rpg .user-text,
.chat.character .edit-area,
.chat.rpg .edit-area {
    font-family: var(--serif);
    font-size: 1.02rem;
    line-height: 1.7;
}

/* Character dialogue in asymmetric bubbles: the cast speaks from the left,
   you answer from the right. */
.chat.character .msg { border-bottom: none; padding: 10px 0; }

.chat.character .msg-content {
    flex: 0 1 auto;
    min-width: 0;
    max-width: min(86%, 620px);
    background: var(--card-bg);
    border: 1px solid var(--border-soft);
    border-radius: 4px 14px 14px 14px;
    padding: 10px 14px;
}

.chat.character .msg-user { flex-direction: row-reverse; }

.chat.character .msg-user .msg-content {
    background: rgba(37, 99, 235, 0.13);
    border-color: rgba(59, 115, 235, 0.32);
    border-radius: 14px 4px 14px 14px;
}

.chat.character .msg-user .msg-role { text-align: right; color: #8fb0e8; }

.chat.character .msg-assistant .msg-role {
    color: var(--ember);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    font-size: 0.72rem;
}

/* Tool results (dice rolls, generated art) stay free of the bubble chrome. */
.chat.character .msg-tool .msg-content {
    background: none;
    border: none;
    padding: 0;
    max-width: 100%;
    flex: 1;
}

/* Per-message action buttons align their icon and label. */
.msg-action {
    display: inline-flex;
    align-items: center;
    gap: 5px;
}

.msg-action.msg-action-danger:hover { color: var(--danger); }

/* ---- Voice profile (Characters editor), audition/lineup rounds, keep-line -- */
.voice-profile .field-row { margin-top: 8px; }

.voice-line {
    border: 1px solid var(--border-soft);
    border-radius: 8px;
    padding: 6px 10px;
    margin: 6px 0;
}

.voice-line-head { display: flex; align-items: center; gap: 8px; }

.voice-line-head .muted {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.voice-line-remove { margin-left: auto; }

.voice-line-source {
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    padding: 1px 7px;
    border-radius: 999px;
    border: 1px solid var(--border-soft);
    color: var(--text-muted);
    white-space: nowrap;
}

.voice-line-source.play { border-color: var(--ember); color: var(--ember); }
.voice-line-source.audition { border-color: var(--accent); color: var(--accent); }

.voice-line-text { white-space: pre-wrap; margin-top: 4px; line-height: 1.5; }

.voice-line-add { align-items: flex-start; margin-top: 8px; }

.audition-card {
    display: flex;
    flex-direction: column;
    gap: 8px;
    background: var(--bg-elevated);
    border: 1px solid var(--border-soft);
    border-radius: 10px;
    padding: 10px 12px;
}

.audition-line {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 10px;
    border: 1px solid var(--border-soft);
    border-radius: 8px;
    padding: 6px 10px;
}

.audition-line.keep { border-color: var(--accent); background: var(--accent-soft); }
.audition-line.wrong { opacity: 0.6; }
.audition-line.wrong .audition-line-text { text-decoration: line-through; }

.audition-line-text { flex: 1; min-width: 200px; white-space: pre-wrap; line-height: 1.5; }

.audition-line-btns { display: flex; gap: 6px; flex: 0 0 auto; }

.lineup-select { width: auto; min-width: 160px; flex: 0 0 auto; }

.keep-line-row { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; }

.keep-line-text { flex: 1; min-width: 200px; font-style: italic; }

.keep-line-select { width: auto; min-width: 150px; flex: 0 0 auto; }

.revise-presets { display: flex; gap: 6px; flex-wrap: wrap; }

/* ==================== Mobile overrides (≤768px) ==========================
   Kept at the END of the stylesheet on purpose: these re-style selectors
   whose base rules appear throughout the file, and at equal specificity
   the later declaration must win. Desktop (>768px) is untouched. */
@media (max-width: 768px) {
    /* One compact row: hamburger (fixed, 58px cleared on the left), the
       model picker filling the rest, and the tuning chip. The cast bar wraps
       onto its own full-width row below. `.chat .chat-topbar` outranks the
       desktop assistant rule so the safe-area padding wins here: in the
       installed (home-screen) app the status bar overlays the page, and a
       row without this inset sits behind it, out of reach. */
    .chat .chat-topbar {
        height: auto;
        min-height: 0;
        flex-wrap: wrap;
        gap: 6px 8px;
        padding: calc(8px + env(safe-area-inset-top, 0px)) 12px 6px 12px;
    }
    /* Only the first row has to clear the hamburger; the cast bar below it
       and the assistant strip get the full width. */
    .model-picker-main, .rpg-topbar { margin-left: 46px; }

    .model-picker select { max-width: min(340px, 46vw); min-height: 34px; padding: 5px 10px; }

    /* The select's own text names the model; the label only costs width. */
    .model-picker-main { flex: 1 1 0; min-width: 0; }
    .model-picker-main label {
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip: rect(0 0 0 0);
        white-space: nowrap;
    }
    .model-picker-main select { width: 100%; max-width: none; }

    /* Thinking + prompt fold into a sheet behind one chip (aligned with the
       36px select beside it). */
    .rpg-chip.tuning-toggle {
        display: inline-flex;
        flex: 0 0 auto;
        min-height: 34px;
        padding: 4px 10px;
        color: var(--text);
    }
    .tuning-pickers { display: none; }
    .tuning-pickers.open {
        display: flex;
        flex-direction: column;
        gap: 12px;
        position: fixed;
        left: 12px;
        right: 12px;
        top: 50%;
        transform: translateY(-50%);
        z-index: 60;
        padding: 14px;
        background: var(--card-bg);
        border: 1px solid var(--border);
        border-radius: 12px;
        box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45);
    }
    .tuning-pickers.open .model-picker { justify-content: space-between; gap: 12px; }
    .tuning-pickers.open .model-picker label { flex: 0 0 auto; }
    .tuning-pickers.open .model-picker select { flex: 1 1 auto; min-width: 0; max-width: none; }
    .tuning-done { display: inline-block; align-self: flex-end; }

    /* The cast bar becomes one horizontally-scrollable row (the RPG chip
       bar's pattern) so a large cast can't eat the whole screen. */
    .cast-bar {
        flex: 1 1 100%;
        min-width: 0;
        flex-wrap: nowrap;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        scrollbar-width: none;
        padding-bottom: 2px;
    }
    .cast-bar::-webkit-scrollbar { display: none; }

    /* Topbar dropdowns (story clock, thread settings, add-cast) would be
       clipped by the scrolling bar and overflow the right edge when anchored
       to their chip — centered fixed sheets instead. */
    .cast-add-menu {
        position: fixed;
        left: 12px;
        right: 12px;
        top: 50%;
        transform: translateY(-50%);
        min-width: 0;
        max-height: min(76vh, 560px);
        overflow-y: auto;
        z-index: 60;
    }
    .thread-settings-menu { min-width: 0; }
    .scene-ledger-editor { min-width: 0; }

    /* Side panels (RPG party & journal, character portrait) go full-screen;
       each carries its own close button. Also frees them from the desktop
       top:52px anchor, which no longer matches the wrapping topbar. */
    .rpg-panel,
    .cast-portrait-pane {
        position: fixed;
        inset: 0;
        width: 100%;
        z-index: 45;
        box-shadow: none;
        padding-top: calc(14px + env(safe-area-inset-top, 0px));
        padding-bottom: calc(24px + env(safe-area-inset-bottom, 0px));
    }

    /* The scene backdrop shades the whole column; the topbar (opaque, on
       top) keeps its own band readable whatever height it wraps to. */
    .rpg-backdrop { top: 0; }

    /* Recap overlay: hand the card nearly the whole screen (clear of the
       status bar in the installed app). */
    .rpg-recap-overlay { padding: calc(12px + env(safe-area-inset-top, 0px)) 12px 12px; }
    .rpg-recap { padding: 18px 16px; max-height: 92%; }

    /* Touch has no hover: per-thread rename/delete stay visible. */
    .thread-rename, .thread-delete { opacity: 1; }

    /* Same for the chapter-boundary nudge chevrons on the dividers. */
    .chapter-boundary-btn { opacity: 0.75; }

    /* Message action rows (try again / edit / speak / roll back) wrap
       instead of running past the right edge. */
    .msg-actions { flex-wrap: wrap; row-gap: 4px; }

    /* Media can never exceed the message column (tool images are generated
       at up to 420px, wider than small phones). */
    .attach-thumb, .msg-tool .attach-thumb { max-width: 100%; }
    .markdown table { display: block; max-width: 100%; overflow-x: auto; }

    /* Card headers and action rows (title + buttons) may wrap. */
    .card-head { flex-wrap: wrap; gap: 8px; }
    .card-actions { flex-wrap: wrap; }

    /* iOS force-zooms into focused controls set below 16px — meet it so the
       page never jumps when a field or the composer is tapped. */
    input, select, textarea, .composer textarea { font-size: 16px; }
    .chat.character .edit-area, .chat.rpg .edit-area { font-size: 16px; }
}
