/* ===========================================================================
   Rusty chat — the visual layer for the in-app assistant.
   The streaming driver (RustyChatUiDriver) writes this DOM through JS interop;
   nothing here is rendered by Blazor, so every class below must exist or the
   panel degrades to anonymous boxes. Colours ride the Falcon theme tokens so
   the chat reads as part of OrderBooks rather than a pasted-in widget.
   =========================================================================== */

/* The tokens live on every Rusty ROOT, not just .rusty-chat: the history column and the overlay
   chrome sit OUTSIDE the chat panel's element, and a var() consumed where it is not defined is
   invalid at computed-value time — the column's border was silently resolving to nothing. */
.rusty-chat,
.rusty-overlay {
    --rusty-accent: var(--falcon-primary, #2c7be5);
    --rusty-surface: var(--falcon-light-bg-subtle, #fdfefe);
    --rusty-border: var(--falcon-secondary-border-subtle, #c7cdd4);
    --rusty-text: var(--falcon-gray-900, #344050);
    --rusty-muted: var(--falcon-gray-600, #748194);
    --rusty-white: #fff;
}

/* ---- History column (left of the chat) --------------------------------------
   The Bedrock wiki parks this rail in the site's fixed 340px sidebar (spec §3); here it is the
   overlay's left column instead — same internal geometry, adapted to our palette. It sits inside
   .rusty-split, which inherits its height from the overlay's fixed-position panel, so the column
   never breaks the composer-in-view contract. Below 768px the column hides and the chat takes
   the whole width (collapse chosen over a drawer/toggle: no extra chrome, nothing to desync —
   see the media query below). */

.rusty-split {
    display: flex;
    flex: 1;
    min-height: 0;
    gap: 0;
}

.rusty-convo-col {
    flex-shrink: 0;
    width: 340px; /* the wiki's --sidebar-width, verbatim */
    border-right: 1px solid var(--rusty-border);
    background: var(--rusty-surface);
    display: flex;
    flex-direction: column;
    min-height: 0;
}

.rusty-convo {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
}

.rusty-convo-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0.75rem 1rem;
    border-bottom: 1px solid var(--rusty-border);
}

.rusty-convo-title {
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--rusty-text);
}

.rusty-convo-new {
    background: none;
    border: 1px solid var(--rusty-border);
    border-radius: 6px;
    padding: 4px 8px;
    cursor: pointer;
    color: var(--rusty-muted);
    display: flex;
    align-items: center;
    transition: all 0.15s;
}

.rusty-convo-new:hover {
    background: var(--falcon-primary-bg-subtle, #d9e7fa);
    color: var(--rusty-text);
}

.rusty-convo-list {
    flex: 1;
    overflow-y: auto;
    padding: 0.5rem;
}

.rusty-convo-empty {
    text-align: center;
    color: var(--rusty-muted);
    font-size: 0.85rem;
    padding: 2rem 1rem;
}

.rusty-convo-row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 0.5rem 0.5rem 0.75rem;
    border-radius: 8px;
    color: var(--rusty-text);
    font-size: 0.85rem;
    transition: background 0.15s;
}

.rusty-convo-item-link {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex: 1;
    min-width: 0;
    cursor: pointer;
}

.rusty-convo-row:hover {
    background: var(--falcon-primary-bg-subtle, #eff6ff);
}

/* Active row = ACCENT BACKGROUND, not just bold/highlight (spec §3.2). */
.rusty-convo-row.active {
    background: var(--rusty-accent);
    color: var(--rusty-white);
}

.rusty-convo-item-icon {
    flex-shrink: 0;
    font-size: 0.9rem;
}

.rusty-convo-item-title {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.rusty-convo-item-date {
    flex-shrink: 0;
    font-size: 0.75rem;
    color: var(--rusty-muted);
}

.rusty-convo-row.active .rusty-convo-item-date {
    color: inherit;
    opacity: 0.8;
}

/* Rename / delete replace the date on hover, so the row never changes width (spec §3.2). */
.rusty-convo-item-actions {
    display: none;
    align-items: center;
    gap: 2px;
    flex-shrink: 0;
}

.rusty-convo-row:hover .rusty-convo-item-actions,
.rusty-convo-row:focus-within .rusty-convo-item-actions {
    display: flex;
}

.rusty-convo-row:hover .rusty-convo-item-date,
.rusty-convo-row:focus-within .rusty-convo-item-date {
    display: none;
}

/* Touch devices never hover, so the actions stay put (spec §3.2). */
@media (hover: none) {
    .rusty-convo-item-actions { display: flex; }
    .rusty-convo-item-date { display: none; }
}

.rusty-convo-action {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    padding: 0;
    border: none;
    border-radius: 6px;
    background: none;
    color: inherit;
    opacity: 0.6;
    cursor: pointer;
    transition: opacity 0.15s, background 0.15s, color 0.15s;
}

.rusty-convo-action:hover {
    opacity: 1;
    background: rgba(var(--falcon-gray-rgb, 116, 129, 148), 0.15);
}

.rusty-convo-action-danger:hover {
    color: var(--falcon-danger, #e63757);
}

.rusty-convo-row.active .rusty-convo-action:hover {
    background: rgba(255, 255, 255, 0.25);
    color: var(--rusty-white);
}

/* Inline rename input (spec §3.2): primary-bordered, replaces the title span in place. */
.rusty-convo-rename-input {
    flex: 1;
    min-width: 0;
    font-family: inherit;
    font-size: 0.85rem;
    padding: 2px 6px;
    border: 1px solid var(--rusty-accent);
    border-radius: 6px;
    background: var(--rusty-white);
    color: var(--rusty-text);
    outline: none;
}

/* Below ~768px (the wiki's own responsive threshold): the column yields the whole width to the
   chat. Chosen COLLAPSE OVER DRAWER/TOGGLE deliberately — a drawer adds chrome and a state to
   desync, and the New-conversation button in the page header already covers "start fresh", so on
   a phone the history is simply not worth stealing the only real estate. Hiding (not shrinking)
   keeps the measured-height contract intact: the split just becomes the panel alone. */
@media (max-width: 768px) {
    .rusty-convo-col { display: none; }
}

/* ---- Log ------------------------------------------------------------------ */

/* THE scroller of the page's flex chain: grows into whatever the header left, never less than
   zero, and scrolls INTERNALLY so the page itself never scrolls. Mirrors the spec's
   .chat-messages verbatim. Inside the Process All modal the parent is not a sized flex column,
   so flex:1 is inert there and the MAXLOGHEIGHT bound passed by the modal takes over instead. */
.rusty-log {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    background: transparent;
    border: none;
    padding: 0.25rem 0.25rem 0.5rem;
}

/* Idle greeting until the first message lands — CENTRED in the log (spec §2.6: margin:auto,
   column-centred, muted). */
.rusty-empty {
    margin: auto;
    text-align: center;
    color: var(--rusty-muted);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.5rem;
    animation: rusty-fade-in 0.2s ease;
}

.rusty-empty-glyph { font-size: 2.25rem; line-height: 1; }

.rusty-empty-title {
    margin-top: 0.5rem;
    font-size: 1.05rem;
    font-weight: 600;
    color: var(--rusty-text);
}

.rusty-empty-hint {
    margin-top: 0.25rem;
    font-size: 0.85rem;
    max-width: 34ch;
    margin-inline: auto;
}

/* ---- Messages ------------------------------------------------------------- */

/* Row max-width min(800px, 85%) — the wiki's .chat-message value verbatim (spec §2.5). */
.rusty-bubble {
    display: flex;
    gap: 0.75rem;
    align-self: flex-start;
    max-width: min(800px, 85%);
    animation: rusty-fade-in 0.2s ease;
}

.rusty-bubble-user {
    align-self: flex-end;
    flex-direction: row-reverse;
}

/* 32px circles — the wiki's .chat-message-avatar value verbatim (spec §2.4). */
.rusty-avatar {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.72rem;
    font-weight: 600;
    overflow: hidden;
    user-select: none;
}

.rusty-avatar-assistant {
    background: linear-gradient(135deg, var(--falcon-orange, #fd7e14), var(--falcon-red, #e63757));
    color: var(--rusty-white);
    font-size: 0.95rem;
}

.rusty-avatar-user {
    background: var(--falcon-primary-bg-subtle, #d9e7fa);
    color: var(--falcon-primary-text-emphasis, #215cac);
    border: 1px solid var(--falcon-primary-border-subtle, #abcaf5);
}

.rusty-bubble-frame {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    min-width: 0;
}

.rusty-bubble-body {
    padding: 0.55rem 0.85rem;
    border-radius: 12px;
    font-size: 0.925rem;
    line-height: 1.5;
    color: var(--rusty-text);
    word-wrap: break-word;
    overflow-wrap: break-word;
    white-space: pre-wrap;
    width: fit-content;
    max-width: 100%;
}

/* A whisper of lift keeps bubbles legible against the near-white page — the border alone
   reads as "half a card" where the surface colours are this close. */
.rusty-bubble-assistant .rusty-bubble-body {
    background: var(--rusty-surface);
    border: 1px solid var(--rusty-border);
    box-shadow: 0 1px 3px rgba(11, 23, 39, 0.06);
}

.rusty-bubble-user .rusty-bubble-body {
    background: var(--rusty-accent);
    border: 1px solid var(--rusty-accent);
    color: var(--rusty-white);
    box-shadow: 0 1px 3px rgba(var(--falcon-primary-rgb, 44, 123, 229), 0.25);
}

/* Markdown inside bubbles */
.rusty-bubble-body > *:first-child { margin-top: 0; }
.rusty-bubble-body > *:last-child { margin-bottom: 0; }
.rusty-bubble-body p { margin: 0 0 0.5rem; }
.rusty-bubble-body h1, .rusty-bubble-body h2, .rusty-bubble-body h3,
.rusty-bubble-body h4 { margin: 0.6rem 0 0.3rem; font-size: 1rem; }
.rusty-bubble-body ul, .rusty-bubble-body ol { margin: 0 0 0.5rem; padding-left: 1.3rem; }
.rusty-bubble-body li { margin-bottom: 0.15rem; }
.rusty-bubble-body code {
    background: rgba(var(--falcon-gray-rgb, 116, 129, 148), 0.14);
    border-radius: 4px;
    padding: 0.05rem 0.3rem;
    font-size: 0.85em;
    font-family: 'JetBrains Mono', monospace;
}
.rusty-bubble-body pre {
    background: rgba(var(--falcon-gray-rgb, 116, 129, 148), 0.1);
    border-radius: 8px;
    padding: 0.6rem 0.75rem;
    overflow-x: auto;
    margin: 0 0 0.5rem;
}
.rusty-bubble-body pre code { background: none; padding: 0; }
.rusty-bubble-body blockquote {
    border-left: 3px solid var(--rusty-border);
    margin: 0 0 0.5rem;
    padding-left: 0.6rem;
    color: var(--rusty-muted);
}
.rusty-bubble-body table { border-collapse: collapse; margin: 0 0 0.5rem; }
.rusty-bubble-body th, .rusty-bubble-body td {
    border: 1px solid var(--rusty-border);
    padding: 0.25rem 0.5rem;
    font-size: 0.85em;
}
.rusty-bubble-body strong { font-weight: 600; }

/* User bubble markdown keeps contrast on the accent background */
.rusty-bubble-user .rusty-bubble-body code { background: rgba(255, 255, 255, 0.22); }
.rusty-bubble-user .rusty-bubble-body pre { background: rgba(0, 0, 0, 0.18); }
.rusty-bubble-user .rusty-bubble-body blockquote { border-left-color: rgba(255, 255, 255, 0.5); color: rgba(255, 255, 255, 0.85); }

/* ---- Thinking panel --------------------------------------------------------
   The model's reasoning lives in its OWN labelled region: muted colour, dashed
   border, smaller type, and it folds away + relabels "Thoughts" the moment the
   answer starts speaking. It can never read as the answer. */

.rusty-thinking {
    font-size: 0.8rem;
    border: 1px dashed var(--rusty-border);
    border-radius: 10px;
    background: transparent;
    max-width: 100%;
    width: fit-content;
}

.rusty-thinking summary {
    cursor: pointer;
    list-style: none;
    padding: 0.35rem 0.7rem;
    color: var(--rusty-muted);
    user-select: none;
}

.rusty-thinking summary::-webkit-details-marker { display: none; }

.rusty-thinking summary::before { content: '\25B8 '; } /* ▸ */
.rusty-thinking[open] summary::before { content: '\25BE '; } /* ▾ */

.rusty-thinking-text {
    padding: 0 0.7rem 0.5rem;
    color: var(--rusty-muted);
    white-space: pre-wrap;
    max-height: 220px;
    overflow-y: auto;
    line-height: 1.45;
}

/* ---- Working indicator ---------------------------------------------------- */

.rusty-bubble-meta {
    display: flex;
    align-items: center;
    gap: 0.45rem;
    min-height: 1.1em;
    font-size: 0.8rem;
    color: var(--rusty-muted);
}

.rusty-status-text { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 40ch; }

/* 8px dots — the wiki's .typing-indicator value verbatim (spec §2.7). */
.rusty-dots { display: inline-flex; gap: 4px; }

.rusty-dots span {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--rusty-muted);
    animation: rusty-typing 1.4s infinite both;
}

.rusty-dots span:nth-child(2) { animation-delay: 0.2s; }
.rusty-dots span:nth-child(3) { animation-delay: 0.4s; }

@keyframes rusty-typing {
    0%, 60%, 100% { opacity: 0.3; transform: scale(0.8); }
    30% { opacity: 1; transform: scale(1); }
}

@keyframes rusty-fade-in {
    from { opacity: 0; transform: translateY(6px); }
    to { opacity: 1; transform: translateY(0); }
}

/* ---- Composer -------------------------------------------------------------- */

/* Centred composer WRAPPER (spec §2.3): max-width 860px, margin auto — the same 860px column
   the wiki centres its messages on. The wrapper itself is the bordered pill. */
.rusty-composer {
    display: flex;
    gap: 0.5rem;
    align-items: center;
    /* Pinned: whatever the header and log take, the input bar stays in view. The whole point of
       the measured page height is that typing never requires scrolling the page. */
    flex-shrink: 0;
    max-width: 860px;
    width: 100%;
    margin: 0 auto;
    background: var(--rusty-surface);
    border: 1px solid var(--rusty-border);
    border-radius: 12px;
    padding: 0.375rem 0.375rem 0.375rem 0.5rem;
    transition: border-color 0.15s;
}

.rusty-composer:focus-within { border-color: var(--rusty-accent); }

.rusty-composer input[type="text"] {
    flex: 1;
    border: none;
    background: transparent;
    padding: 8px;
    font-size: 0.925rem;
    line-height: 20px;
    min-height: 36px;
    outline: none;
    color: var(--rusty-text);
}

.rusty-composer input[type="text"]::placeholder { color: var(--rusty-muted); }

/* ONE circular button that MORPHS to Stop mid-stream (spec §2.3): 36px circle, primary at rest,
   danger while streaming. Both glyphs exist from first paint (FontAwesome converts both at load),
   so the swap is pure CSS off the rusty-busy class the driver toggles — no re-render involved. */
.rusty-send-btn {
    flex-shrink: 0;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background: var(--rusty-accent);
    color: var(--rusty-white);
    border: none;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: opacity 0.15s, background 0.15s;
}

.rusty-send-btn:hover { opacity: 0.85; }

.rusty-glyph-stop { display: none; }

.rusty-composer.rusty-busy .rusty-send-btn {
    background: var(--falcon-danger, #e63757);
}

.rusty-composer.rusty-busy .rusty-glyph-send { display: none; }
.rusty-composer.rusty-busy .rusty-glyph-stop { display: block; }

/* ---- Inside the Process All modal ------------------------------------------ */

.modal-dialog .rusty-log {
    background: var(--rusty-surface);
    border: 1px solid var(--rusty-border);
    border-radius: 8px;
    padding: 0.75rem;
}

/* ---- The overlay --------------------------------------------------------------
   Rusty pulled out OVER the current page from the topbar pug, so a chat can be spun up anywhere
   without losing the page. The wiki's chat is a full page; the overlay housing is ours, but the
   containment rules inside it are the wiki's, cloned: overflow hidden at the shell, min-height 0
   down the flex chain, the LOG as the one and only scroller, the composer pinned. Open/close is
   a pure JS class toggle (RustyOverlay never re-renders — the log's DOM belongs to the driver),
   and display:none stays OFF the closed state on purpose: the panel's DOM must survive closing,
   so the overlay hides by visibility, which keeps layout alive and interaction dead. */

.rusty-overlay {
    position: fixed;
    inset: 0;
    /* Above the modal stack (1050 + 10 per nested modal): Rusty must be callable OVER a dialog
       showing an error, which is one of his jobs. */
    z-index: 2000;
    visibility: hidden;
    pointer-events: none;
}

.rusty-overlay.rusty-overlay-out {
    visibility: visible;
    pointer-events: auto;
}

.rusty-overlay-backdrop {
    position: absolute;
    inset: 0;
    background: rgba(15, 23, 42, 0.45);
    opacity: 0;
    transition: opacity 0.2s ease;
}

.rusty-overlay-out .rusty-overlay-backdrop {
    opacity: 1;
}

.rusty-overlay-panel {
    position: absolute;
    inset: 16px;
    display: flex;
    flex-direction: column;
    min-height: 0;
    /* The site styles bare <section> with 120px vertical padding; unneutralised it shoves the
       header a hundred pixels down INSIDE the panel (measured) and steals the log's height. */
    padding: 0;
    background: var(--falcon-body-bg, var(--rusty-white));
    border: 1px solid var(--rusty-border);
    border-radius: 12px;
    box-shadow: 0 24px 64px rgba(15, 23, 42, 0.35);
    overflow: hidden;
    overscroll-behavior: contain;
    transform: translateY(-24px);
    opacity: 0;
    transition: transform 0.25s ease, opacity 0.2s ease;
}

.rusty-overlay-out .rusty-overlay-panel {
    transform: translateY(0);
    opacity: 1;
}

.rusty-overlay-header {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 16px;
    border-bottom: 1px solid var(--rusty-border);
}

.rusty-overlay-pug {
    width: 28px;
    height: 28px;
    border-radius: 50%;
}

.rusty-overlay-title {
    font-weight: 600;
    color: var(--rusty-text);
}

.rusty-overlay-spacer {
    flex: 1;
}

.rusty-overlay-btn {
    background: none;
    border: 1px solid var(--rusty-border);
    border-radius: 6px;
    padding: 4px 10px;
    color: var(--rusty-muted);
    cursor: pointer;
    font-size: 0.85rem;
}

.rusty-overlay-btn:hover {
    color: var(--rusty-accent);
    border-color: var(--rusty-accent);
}

/* The split inside the overlay needs no measuring JS: the panel is FIXED-position, so its height
   is exact by construction and the ordinary flex chain (flex:1, min-height:0) does the rest. */
.rusty-overlay-split {
    flex: 1;
    min-height: 0;
}

/* The chat panel inside the overlay breathes like the wiki's log. */
.rusty-overlay .rusty-chat {
    padding: 0 1rem 1rem;
}

/* The wiki centres an 860px conversation column inside however wide the shell is
   (.chat-messages' padding formula, verbatim); the composer matches the column. */
.rusty-overlay .rusty-log {
    padding: 1.25rem max(1rem, calc((100% - 860px) / 2));
}

.rusty-overlay .rusty-composer {
    width: 100%;
    max-width: 860px;
    margin: 0 auto;
}

/* While the overlay is out the PAGE underneath must not scroll — same document-lock idea as the
   /rusty route class, scoped to a class RustyOverlay toggles on <html>. */
html.rusty-overlay-open {
    overflow: hidden;
}

/* ---- Workshop mode chrome ------------------------------------------------------
   The wiki marks its workshop with a warning accent on assistant replies and a badge; both are
   toggled by the panel through JS from the conversation's mode, never by a re-render. */
.rusty-mode-badge {
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--falcon-warning, #f5803e);
    border: 1px solid var(--falcon-warning, #f5803e);
    border-radius: 999px;
    padding: 2px 8px;
}

.rusty-workshop .rusty-bubble-assistant .rusty-bubble-frame {
    border-left: 3px solid var(--falcon-warning, #f5803e);
}

/* The topbar pug: an image in a standard .ob-topbar-btn slot. */
.ob-topbar-rusty-icon {
    width: 22px;
    height: 22px;
    border-radius: 50%;
    display: block;
}

@media (prefers-reduced-motion: reduce) {
    .rusty-bubble, .rusty-dots span { animation: none; }
    .rusty-overlay-panel, .rusty-overlay-backdrop { transition: none; }
}
