/* ==========================================================================
   ai-assistant.css — AI assistant / Lens styles

   All AI/Lens CSS, extracted from app.css to keep the AI surfaces isolated.
   Used by the Lens side panel (ai-assistant.js) and the AI-assisted builders
   in Reports, Export, and the Survey Series builder. Depends on the :root
   custom properties declared in html.css (loaded first) and on the shared
   icons in icons.css (.icon-ai, .icon-lens). Mobile overrides for these
   surfaces live in mobile.css per the project's mobile-CSS convention.
   ========================================================================== */

/* ========== Lens assistant side panel ==========
   Slide-in panel shell only. The chat surface inside it is the shared
   Core.aiChat widget (.ai-composer-* / .ai-chat-*), so this block styles just
   the toggle button, overlay, panel container, and header. */

/* Header Lens button — 32px lens icon only, no button chrome. */
.ai-assistant-toggle-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    padding: 0;
    border: none;
    background: none;
    border-radius: 6px;
    cursor: pointer;
    margin-left: 0.75rem;
    transition: background 0.15s;
}
.ai-assistant-toggle-btn:hover {
    background: var(--primary-bg-light);
}
.ai-assistant-toggle-btn.active {
    background: var(--primary-light);
}

/* Overlay */
.ai-assistant-overlay {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.2);
    z-index: 999;
}
.ai-assistant-overlay.open {
    display: block;
}

/* Panel */
.ai-assistant-panel {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    /* Width is session-resizable via the left-edge drag handle: ai-assistant.js
       sets --lens-panel-width on this element (persisted in sessionStorage). */
    width: var(--lens-panel-width, 546px);
    max-width: 100vw;
    background: #fff;
    box-shadow: -2px 0 12px rgba(0, 0, 0, 0.12);
    z-index: 1000;
    display: flex;
    flex-direction: column;
    transform: translateX(100%);
    transition: transform 0.25s ease;
}
.ai-assistant-panel.open {
    transform: translateX(0);
}

/* Left-edge drag handle to resize the panel width (desktop only; hidden on
   mobile in mobile.css). A thin grab strip that highlights on hover/drag. */
.ai-assistant-resize-handle {
    position: absolute;
    top: 0;
    left: 0;
    bottom: 0;
    width: 6px;
    cursor: ew-resize;
    z-index: 2;
    transition: background 0.15s;
}
.ai-assistant-resize-handle:hover,
.ai-assistant-resize-handle.dragging {
    background: var(--primary-light);
}
/* Suppress text selection and keep the resize cursor while dragging. */
body.lens-resizing {
    cursor: ew-resize;
    user-select: none;
}

/* Panel header */
.ai-assistant-panel-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0.75rem 1rem;
    border-bottom: 1px solid var(--border-color);
    flex-shrink: 0;
}
.ai-assistant-panel-title {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    font-weight: 600;
    font-size: 1rem;
}
.ai-assistant-panel-actions {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}
.ai-assistant-panel-close {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border: none;
    background: none;
    font-size: 1.3rem;
    color: var(--text-muted);
    cursor: pointer;
    border-radius: 4px;
}
.ai-assistant-panel-close:hover {
    background: #f0f0f0;
    color: var(--text-color);
}

/* The shared chat widget fills the rest of the panel below the header, with a
   comfortable inset so the messages and composer aren't flush to the panel edges. */
.ai-assistant-panel .ai-chat-mount,
.ai-assistant-panel .ai-composer-composer {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
}
.ai-assistant-panel .ai-chat-mount {
    padding: 0.75rem 1rem 1rem;
}

/* ── AI builder definition summary "data chain" (shared) ────────────
   Shared/global across every AI-assisted builder — Reports, Export, and the
   Survey Series builder. Read-only projection of the working definition: a
   chain of chips (e.g. datasource → filters → measure → dimension → chart, or
   the series sentence) with connector words. Editable chips open focused
   stacked editors; "Edit fields" opens the full section builder. The
   `.ai-summary-chain` + `.ai-summary-conn` chain primitives are the pieces
   reused everywhere; chips reuse the .template-chip family. */
.ai-summary-header {
    margin-bottom: 0.5rem;
}
.ai-summary-titlerow {
    display: flex;
    align-items: center;
    gap: 0.75rem;
}
.ai-summary-title {
    font-size: 1.1rem;
    font-weight: 600;
    color: var(--text-color);
}
.ai-summary-desc {
    margin-top: 0.35rem;
    font-size: 0.875rem;
    line-height: 1.5;
    color: var(--text-muted);
}
/* Instruction banner + Edit All button — full-bleed across the modal body
   (negative margins cancel the .popupBox-body 0.5rem 1rem padding). */
.ai-summary-banner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    margin: 0.85rem -1rem 0;
    padding: 0.6rem 1rem;
    background: var(--primary-bg-light);
    border-top: 1px solid var(--border-color);
    border-bottom: 1px solid var(--border-color);
    font-size: 0.8rem;
    color: var(--text-muted);
}
.ai-summary-banner > span {
    flex: 1 1 auto;
    text-align: right;
}
.ai-summary-banner .button {
    flex: 0 0 auto;
}
/* Each section is its own bordered fieldset (no separators between them). */
.ai-summary-section {
    border: 1px solid var(--border-color);
    border-radius: 6px;
    padding: 0.4rem 0.85rem 0.75rem;
    margin: 0.85rem 0 0;
    min-width: 0;
}
.ai-summary-legend {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.4rem;
    padding: 0 0.4rem;
    width: auto;
    border: none;
    margin: 0;
    font-size: inherit;
}
.ai-summary-section-pos {
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-muted);
    margin-right: 0.25rem;
}
.ai-summary-chain {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.45rem 0.5rem;
    line-height: 2;
}
/* Chips breathe more inside the summary than the default 20px template chip. */
.ai-summary-chain .template-chip,
.ai-summary-legend .template-chip {
    height: auto;
    padding: 0.3rem 0.6rem;
    font-size: 0.8rem;
    border-radius: 8px;
}
/* Connector words read the chain as a sentence. */
.ai-summary-conn {
    color: var(--text-muted);
    font-size: 0.8rem;
    font-style: italic;
}
/* Editable affordance on chips, title, and description. */
.ai-summary-chip--editable {
    cursor: pointer;
    transition: filter 0.15s ease, background 0.15s ease;
}
.ai-summary-chain .ai-summary-chip--editable:hover {
    filter: brightness(0.95);
}
.ai-summary-title.ai-summary-chip--editable:hover,
.ai-summary-desc.ai-summary-chip--editable:hover {
    text-decoration: underline;
}
.ai-summary-chip--editable:focus-visible {
    outline: 2px solid var(--primary-color);
    outline-offset: 1px;
}

/* ── Lens AI chat composer (lives in the modal subheader) ───────────
   One composer, repurposed for initial generation and refinement; the
   placeholder is the only difference. Light-blue subheader band wraps
   a white rounded input with a hint + send button row below it. */
.popupBox-subheader.ai-composer-subheader {
    padding: 1rem;
    border-bottom: 1px solid var(--border-color);
    font-weight: 400;
    /* A flex region of the popup (both phases): the chat transcript scrolls
       inside it while the input row stays pinned below, and the modal grows to
       fit content up to its 95vh cap — sharing space with the body (chip flow)
       in form phase. Header and footer stay pinned. (Default subheaders are
       flex-shrink:0, which would let tall content push the footer off-screen.) */
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}
/* Transparent flex passthrough: the Core.aiChat widget mounts its composer into
   this node, so it must not interrupt the subheader→composer flex chain. */
.ai-composer-subheader .ai-chat-mount {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
}
.ai-composer-subheader .ai-composer-composer {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
}
/* Input row + hint/buttons stay fixed below the scrolling transcript. */
.ai-composer-subheader .ai-composer-input-row,
.ai-composer-subheader .ai-composer-foot {
    flex-shrink: 0;
}
/* Keep the chip-chain summary always visible across the AI builder modals
   (Series / Reports / Exports). The summary lives in .popupBox-body — the
   sibling right after the chat subheader. By default the body is flex:1 1 auto
   and shares space with the subheader, so a growing chat squeezed the summary
   smaller and smaller. Here the summary instead sizes to its content (capped,
   scrolling internally if very tall) and never yields; the chat subheader
   (flex:1 1 auto) absorbs the remaining space and scrolls its transcript. In
   the prompt phase the body is display:none, so this has no effect until a
   summary exists. */
.popupBox-subheader.ai-composer-subheader + .popupBox-body {
    flex: 0 0 auto;
    max-height: 40vh;
    border-top: 2px solid var(--border-color);
}
/* The chat-box chrome (border/bg/radius/padding) lives on the row so the AI glyph
   sits inside the border, beside the contenteditable. */
.ai-composer-input-row {
    display: flex;
    align-items: flex-start;
    gap: 0.55rem;
    background: #f1f3f4;
    border: 1px solid #c9cfd3;
    border-radius: 8px;
    padding: 0.55rem 0.85rem;
}
.ai-composer-input-row .icon-ai {
    flex: 0 0 auto;
    margin-top: 2px;
}
.ai-composer-input {
    flex: 1;
    min-width: 0;
    margin: 0;
    padding: 0;
    background: transparent;
    border: none;
    border-radius: 0;
    min-height: 4em;
    max-height: 9em;
    overflow-y: auto;
    outline: none;
    font-size: 0.9rem;
    line-height: 1.4;
    color: var(--text-color);
    white-space: pre-wrap;
    word-break: break-word;
}
.ai-composer-input:empty:before {
    content: attr(data-placeholder);
    color: var(--text-muted);
    pointer-events: none;
}
/* Dev mode (otDevMode on): red-tinted composer as a persistent "on" cue. */
.ai-composer--dev .ai-composer-input-row {
    background: var(--error-bg-light);
    border-color: var(--error-color);
}
/* Dev mode: "View definition" action block appended below a result. */
.ai-chat-dev-actions {
    margin-top: 0.4rem;
}
.ai-composer-foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    padding: 0.5rem 0 0 0;
}
.ai-composer-foot-actions {
    display: flex;
    align-items: center;
    gap: 0.35rem;
}
.ai-composer-foot-left {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    min-width: 0;
}
.ai-composer-hint {
    font-size: 0.8rem;
    color: var(--text-muted);
}
/* When a New Chat button shares the foot's left side (e.g. the Lens side panel),
   drop the keyboard hint — there isn't room for both in a narrow panel. */
.ai-composer-foot-left:has(.ai-composer-newchat) .ai-composer-hint {
    display: none;
}

/* ── Document upload (drag-and-drop; survey-builder only) ─────────────────────
   The markup below is rendered only when the host opts in (allowUploads), so
   these rules are inert on every other AI surface. */

/* With the drag-to-upload hint present, drop the keyboard hint so the foot
   doesn't carry two hint lines. */
.ai-composer-foot-left:has(.ai-composer-hint--drag) .ai-composer-hint:not(.ai-composer-hint--drag) {
    display: none;
}

/* The composer is the positioning context for the drop overlay — but only when an
   upload-enabled host renders the dropzone, so other surfaces are untouched. */
.ai-composer-composer:has(> .ai-composer-dropzone) {
    position: relative;
}

/* Full-composer drop target, revealed only while a file is dragged over. */
.ai-composer-dropzone {
    position: absolute;
    inset: 0;
    z-index: 5;
    display: none;
    align-items: center;
    justify-content: center;
    border: 2px dashed var(--primary-color);
    border-radius: 8px;
    background: var(--primary-bg-light);
    color: var(--primary-hover);
    font-weight: 600;
    pointer-events: none;
}
.ai-composer-composer.is-dropping .ai-composer-dropzone {
    display: flex;
}

/* Prepped-attachment chip (rendered in the footer attachment bar). */
.ai-composer-attachment-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    max-width: 100%;
    padding: 0.25rem 0.5rem;
    background: var(--primary-light);
    border: 1px solid var(--primary-color);
    border-radius: 14px;
    font-size: 0.82rem;
    color: var(--text-color);
}
.ai-composer-attachment-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 16rem;
}
.ai-composer-attachment-remove {
    flex: none;
    border: none;
    background: transparent;
    cursor: pointer;
    font-size: 1rem;
    line-height: 1;
    color: var(--text-muted);
    padding: 0 0.1rem;
}
.ai-composer-attachment-remove:hover {
    color: var(--danger-color);
}
/* Footer attachment bar — replaces the drag hint once a file is attached: it carries
   the filename, an include-in-next-request switch, and a remove ×. */
.ai-composer-attachbar[hidden] {
    display: none;
}
.ai-composer-attachbar {
    display: inline-flex;
    min-width: 0;
    max-width: 100%;
}
.ai-composer-attachbar .ai-composer-attachment-name {
    max-width: 12rem;
}
.ai-composer-attachment-switch {
    margin-left: 0.15rem;
}
/* While a turn is in flight the send icon is swapped for icon-ai (see
   AiChat.setBusy); pulse it to signal work. Keep the button at full opacity
   despite being disabled so the pulse reads clearly. */
.ai-composer-send.is-working [class^="icon-"] {
    animation: ai-composer-pulse 1.2s ease-in-out infinite;
}
.ai-composer-send.is-working:disabled {
    opacity: 1;
}

/* AI follow-up suggestion chips, rendered at the bottom of the response bubble
   (after the text). A thin rule separates them from the message text. */
.ai-composer-suggestions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    margin-top: 0.5rem;
    padding-top: 0.5rem;
    border-top: 1px solid rgba(0, 0, 0, 0.08);
}
.ai-composer-suggestions:empty {
    display: none;
}
.ai-composer-suggestion-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.2rem;
    padding: 0.2rem 0.45rem;
    font-size: 0.75rem;
    line-height: 1.2;
    white-space: nowrap;
    color: var(--primary-hover);
    background: var(--primary-bg-light);
    border: 1px solid var(--primary-color);
    border-radius: 6px;
    cursor: pointer;
    transition: background 0.12s, border-color 0.12s;
}
.ai-composer-suggestion-chip:hover {
    background: var(--primary-light);
    border-color: var(--primary-hover);
}
/* Already added to the prompt this turn — dimmed and inert until the next turn. */
.ai-composer-suggestion-chip.is-used {
    opacity: 0.4;
    cursor: default;
    pointer-events: none;
}
.ai-composer-suggestion-chip .icon-add {
    flex: 0 0 auto;
    width: 11px;
    height: 11px;
    opacity: 0.8;
}

/* ── Lens starter chips ────────────────────────────────────────────
   Page-aware suggested questions. On a fresh chat they render just above the
   greeting: as the first child of .ai-chat-messages the block gets
   margin-top:auto (below), so the starters + greeting hug the composer
   together and the empty space sits above them. Mid-conversation the host
   appends a starters block at the END of the transcript instead (no auto
   margin — it just follows the last message). */
.ai-composer-starters {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 0.4rem;
    flex: 0 0 auto;
}
.ai-composer-starter-chip {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    width: 100%;
    text-align: left;
    padding: 0.45rem 0.6rem;
    font-size: 0.82rem;
    line-height: 1.3;
    color: var(--primary-hover);
    background: var(--primary-bg-light);
    border: 1px solid var(--primary-light);
    border-radius: 8px;
    cursor: pointer;
    transition: background 0.12s, border-color 0.12s;
}
.ai-composer-starter-chip:hover {
    background: var(--primary-light);
    border-color: var(--primary-color);
}
.ai-composer-starter-chip .icon-help-blue {
    flex: 0 0 auto;
    width: 14px;
    height: 14px;
}
/* Fresh chat: the starters block leads the transcript, so it carries the
   bottom-anchoring auto margin — starters + greeting hug the composer together
   with the open space above them. (Mid-conversation the block is appended at
   the end and is not the first child, so this doesn't apply.) */
.ai-chat-messages > .ai-composer-starters:first-child {
    margin-top: auto;
}

/* ── Lens chat panel ───────────────────────────────────────────────
   The chat panel sits inside ai-composer-subheader, above the compose row.
   Messages stack vertically; user bubbles right-align, AI bubbles
   left-align. Auto-scrolls to the latest message as content streams in. */
.ai-chat-messages {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    /* Grow with the conversation (no fixed cap) so the modal expands to show as
       much of the transcript as fits; scrolls internally only once the popup
       hits its 95vh cap and the composer/body have to share the space. */
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    margin-bottom: 0.75rem;
    padding: 0.25rem 0.1rem;
}
.ai-chat-messages:empty {
    display: none;
}
/* Bottom-anchor the transcript: the first message gets margin-top:auto so all
   content hugs the bottom (just above the composer) while there's free vertical
   space — the greeting starts there, and the conversation grows upward from the
   composer. Once the content overflows the area the auto margin collapses to 0,
   so normal top-down scrolling resumes (newest at the bottom). Preferred over
   justify-content:flex-end, which clips the start of overflow in some browsers. */
.ai-chat-messages > .ai-chat-msg:first-child {
    margin-top: auto;
}
.ai-chat-msg {
    display: flex;
    flex-direction: column;
    max-width: 95%;
}
.ai-chat-msg--user {
    align-self: flex-end;
    align-items: flex-end;
}
.ai-chat-msg--ai {
    align-self: flex-start;
    align-items: flex-start;
}
.ai-chat-bubble {
    padding: 0.55rem 0.85rem;
    border-radius: 12px;
    font-size: 0.9rem;
    line-height: 1.4;
    white-space: pre-wrap;
    word-break: break-word;
}
.ai-chat-msg--user .ai-chat-bubble {
    background: #e8f0fe;
    color: var(--text-color);
    border: 1px solid #abc8fa;
    border-bottom-right-radius: 4px;
}
.ai-chat-msg--ai .ai-chat-bubble {
    background: #fff;
    color: var(--text-color);
    border: 1px solid var(--border-color);
    border-bottom-left-radius: 4px;
}
/* Lens result blocks (appendBlock content) render as full-width cards rather
   than chat bubbles, so charts/tables get the panel's width. */
.ai-chat-msg--block {
    align-self: stretch;
    max-width: 100%;
    width: 100%;
}
/* Narration streams into a bubble inside a block wrapper (charts/tables use a
   .lens-report-result node instead, so this only targets narration). Drop the
   chat-tail radius so the bordered bubble reads as a result card. */
.ai-chat-msg--block .ai-chat-bubble {
    border-bottom-left-radius: 12px;
}
.lens-report-result,
.lens-report-error {
    width: 100%;
    box-sizing: border-box;
    border: 1px solid var(--border-color);
    border-radius: 12px;
    background: #fff;
    padding: 0.6rem 0.75rem;
    font-size: 0.85rem;
}
/* Result bubble hosts the report render plus an absolutely-positioned expand
   button in the top-right corner. */
.lens-report-result {
    position: relative;
}
/* A standalone table carries its own border — drop the bubble chrome so it isn't
   double-bordered. The canvas still pads down to clear the floating expand button. */
.lens-report-result--bare {
    border: none;
    background: none;
    padding: 0;
}
.lens-report-expand {
    position: absolute;
    top: 0.4rem;
    right: 0.4rem;
    z-index: 1;
}
/* Keep the rendered content clear of the expand button. */
.lens-report-result:has(.lens-report-expand) .lens-report-canvas {
    padding-top: 1.4rem;
}
.lens-report-error {
    color: var(--error-color);
    border-color: var(--error-color);
}

/* "Interpret this chart?" suggestion shown under a Lens chart result. Clicking it
   (or typing "explain that") runs the optional narration turn; it removes itself
   once fired. Left-aligned chip-style button, kept subtle so it reads as an
   offer, not a primary action. */
.lens-narrate-suggest {
    display: flex;
    gap: 0.4rem;
    flex-wrap: wrap;
    margin-top: 0.4rem;
}
.lens-narrate-suggest .icon-lens {
    margin-right: 4px;
    vertical-align: text-bottom;
}

/* ── Lens documentation (doc-render) ──────────────────────────────────────────
   The support article body rendered inline in the Lens panel. This is a scoped
   subset of public/support/assets/css/support.css, namespaced under .lens-doc,
   with the support site's --support-* variables mapped to the app's :root
   variables. Only article-BODY classes are included (callouts, steps, figures,
   tables) — no page chrome, layout, reset, or `body` rules — so nothing leaks
   into the rest of the panel. */
.lens-doc-result {
    position: relative;
    width: 100%;
    box-sizing: border-box;
    border: 1px solid var(--border-color);
    border-radius: 12px;
    background: #fff;
    padding: 0.6rem 0.7rem;
}
/* Stacked articles (a multi-article answer) get a separating rule. */
.lens-doc-article-block + .lens-doc-article-block {
    margin-top: 1rem;
    border-top: 1px solid var(--border-color);
    padding-top: 1rem;
}
/* Guide banner — labels which guide (Clinician / Admin) the article is from. */
.lens-doc-banner {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 0.5rem;
    padding: 0.4rem 0.6rem;
    border-radius: 6px;
    margin-bottom: 0.7rem;
}
.lens-doc-banner-title { font-weight: 600; font-size: 0.82rem; color: var(--text-color); }
.lens-doc-banner-guide {
    flex: none;
    font-size: 0.66rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    padding: 0.14rem 0.5rem;
    border-radius: 999px;
    color: #fff;
}
.lens-doc-banner--clinician { background: var(--primary-bg-light); }
.lens-doc-banner--clinician .lens-doc-banner-guide { background: var(--primary-color); }
.lens-doc-banner--admin { background: var(--chip-warning-bg); }
.lens-doc-banner--admin .lens-doc-banner-guide { background: var(--chip-filled-warning-bg); }
/* Keep the first banner's guide pill clear of the absolute expand button. */
.lens-doc-result .lens-doc-article-block:first-child .lens-doc-banner { padding-right: 2rem; }
.lens-doc-footer {
    margin-top: 0.75rem;
    padding-top: 0.6rem;
    border-top: 1px solid var(--border-color);
}
.lens-doc-openlink {
    font-size: 0.82rem;
    color: var(--primary-color);
    text-decoration: none;
    font-weight: 600;
}
.lens-doc-openlink:hover { color: var(--primary-hover); text-decoration: underline; }

/* Article body — scoped typography + the support component classes. */
.lens-doc {
    font-size: 0.85rem;
    line-height: 1.5;
    color: var(--text-color);
}
.lens-doc h2 {
    font-size: 1.02rem;
    margin: 1.2em 0 0.5em;
    line-height: 1.3;
}
.lens-doc h2:first-child { margin-top: 0; }
.lens-doc h3 { font-size: 0.92rem; margin: 1em 0 0.4em; }
.lens-doc p { margin: 0.6em 0; }
.lens-doc ul, .lens-doc ol { margin: 0.6em 0; padding-left: 1.4em; }
.lens-doc li { margin: 0.25em 0; }
.lens-doc img { max-width: 100%; height: auto; }
.lens-doc a { color: var(--primary-color); }

/* support-callout */
.lens-doc .support-callout {
    background: var(--primary-light);
    border-left: 3px solid var(--primary-color);
    padding: 0.8rem 0.9rem;
    border-radius: 4px;
    margin: 1.2em 0;
}
.lens-doc .support-callout--warn { background: var(--chip-warning-bg); border-left-color: var(--warning-color); }
.lens-doc .support-callout--danger { background: var(--chip-error-bg); border-left-color: var(--error-color); }
.lens-doc .support-callout p:last-child { margin-bottom: 0; }

/* support-steps — numbered list with connector line */
.lens-doc .support-steps {
    list-style: none;
    padding: 0;
    counter-reset: lens-step;
    margin: 1.2em 0;
}
.lens-doc .support-steps > li {
    counter-increment: lens-step;
    position: relative;
    padding: 0 0 1.1em 2.4em;
    margin: 0;
}
.lens-doc .support-steps > li::before {
    content: counter(lens-step);
    position: absolute;
    left: 0;
    top: 0;
    width: 1.7em;
    height: 1.7em;
    background: var(--primary-color);
    color: #fff;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-weight: 600;
    font-size: 0.85em;
}
.lens-doc .support-steps > li:not(:last-child)::after {
    content: "";
    position: absolute;
    left: 0.85em;
    top: 1.7em;
    bottom: 0;
    width: 2px;
    background: var(--border-color);
}

/* support-table */
.lens-doc table.support-table {
    width: 100%;
    border-collapse: collapse;
    margin: 1.2em 0;
    font-size: 0.9em;
}
.lens-doc table.support-table th,
.lens-doc table.support-table td {
    text-align: left;
    padding: 0.5em 0.7em;
    border: 1px solid var(--border-color);
}
.lens-doc table.support-table th { background: var(--background-alt); font-weight: 600; }
.lens-doc table.support-table tr:nth-child(even) td { background: var(--background-alt); }

/* Modal context — a touch larger for comfortable reading. */
.lens-doc-modal .lens-doc { font-size: 0.95rem; }

/* AI-bubble color palette. The active color is chosen in reports.js
   (lensBubbleColor() — currently the #2 default); we may later let users pick a
   favorite, so all ten candidates are kept here. */
.ai-chat-msg--ai .ai-chat-bubble.ai-composer-color-1  { background: #e8f0fe; border-color: #abc8fa; }
.ai-chat-msg--ai .ai-chat-bubble.ai-composer-color-2  { background: #e6f4ea; border-color: #a0d5b4; }
.ai-chat-msg--ai .ai-chat-bubble.ai-composer-color-3  { background: #f3e8fd; border-color: #cfaef0; }
.ai-chat-msg--ai .ai-chat-bubble.ai-composer-color-4  { background: #fdeee3; border-color: #f0be99; }
.ai-chat-msg--ai .ai-chat-bubble.ai-composer-color-5  { background: #fef7e0; border-color: #efda82; }
.ai-chat-msg--ai .ai-chat-bubble.ai-composer-color-6  { background: #fde8ec; border-color: #f1a8b7; }
.ai-chat-msg--ai .ai-chat-bubble.ai-composer-color-7  { background: #e0f7f4; border-color: #98dacf; }
.ai-chat-msg--ai .ai-chat-bubble.ai-composer-color-8  { background: #f1f3f4; border-color: #c9cfd3; }
.ai-chat-msg--ai .ai-chat-bubble.ai-composer-color-9  { background: #e3f6fb; border-color: #9cd9e8; }
.ai-chat-msg--ai .ai-chat-bubble.ai-composer-color-10 { background: #f5efe6; border-color: #d9c6a6; }
/* Rendered-markdown assistant bubbles: drop pre-wrap (block elements handle
   spacing) and give the common markdown elements compact, in-bubble styling. */
.ai-chat-bubble--md {
    white-space: normal;
}
.ai-chat-bubble--md > :first-child {
    margin-top: 0;
}
.ai-chat-bubble--md > :last-child {
    margin-bottom: 0;
}
.ai-chat-bubble--md p {
    margin: 0 0 0.6em;
}
.ai-chat-bubble--md ul,
.ai-chat-bubble--md ol {
    margin: 0 0 0.6em;
    padding-left: 1.3em;
}
.ai-chat-bubble--md li {
    margin: 0.15em 0;
}
.ai-chat-bubble--md li > p {
    margin: 0;
}
.ai-chat-bubble--md h1,
.ai-chat-bubble--md h2,
.ai-chat-bubble--md h3,
.ai-chat-bubble--md h4 {
    margin: 0.6em 0 0.35em;
    font-size: 1em;
    font-weight: 600;
    line-height: 1.3;
}
.ai-chat-bubble--md code {
    background: rgba(0, 0, 0, 0.06);
    padding: 0.1em 0.35em;
    border-radius: 4px;
    font-size: 0.88em;
    font-family: ui-monospace, Menlo, Consolas, monospace;
}
.ai-chat-bubble--md pre {
    background: #f5f5f5;
    border: 1px solid var(--border-color);
    border-radius: 6px;
    padding: 0.6em 0.8em;
    overflow-x: auto;
    margin: 0 0 0.6em;
}
.ai-chat-bubble--md pre code {
    background: none;
    padding: 0;
    font-size: 0.95em;
}
.ai-chat-bubble--md a {
    color: var(--primary-color);
    text-decoration: underline;
}
.ai-chat-bubble--md hr {
    border: none;
    border-top: 1px solid var(--border-color);
    margin: 0.7em 0;
}
.ai-chat-bubble--md blockquote {
    margin: 0 0 0.6em;
    padding-left: 0.8em;
    border-left: 3px solid var(--border-color);
    color: var(--text-muted);
}
.ai-chat-bubble--md table {
    border-collapse: collapse;
    margin: 0 0 0.6em;
    font-size: 0.95em;
}
.ai-chat-bubble--md th,
.ai-chat-bubble--md td {
    border: 1px solid var(--border-color);
    padding: 0.3em 0.5em;
    text-align: left;
}
.ai-chat-meta {
    margin-top: 0.25rem;
    font-size: 0.75rem;
    color: var(--text-muted);
}
.ai-chat-msg--ai.is-error .ai-chat-bubble {
    background: #fdecea;
    border-color: var(--error-color);
    color: #611a15;
}
.ai-chat-msg--ai.is-streaming .ai-chat-bubble::after {
    content: '▍';
    margin-left: 2px;
    animation: ai-chat-cursor 1s steps(2) infinite;
}
/* The "Thinking…" placeholder carries its own pulse — suppress the typing cursor. */
.ai-chat-msg--ai.is-streaming .ai-chat-bubble.is-thinking::after {
    content: none;
}
@keyframes ai-chat-cursor {
    50% { opacity: 0; }
}
/* Pre-text streaming placeholder: pulsing AI glyph + "Thinking…". */
.ai-chat-thinking {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    color: var(--text-muted);
    font-style: italic;
}
.ai-chat-thinking-icon {
    animation: ai-composer-pulse 1.2s ease-in-out infinite;
}
@keyframes ai-composer-pulse {
    0%, 100% { opacity: 0.3; }
    50% { opacity: 1; }
}
.ai-composer-history-list {
    display: flex;
    flex-direction: column;
    gap: 1rem;
    max-height: 60vh;
    overflow-y: auto;
    padding: 0.25rem 0.15rem;
}
.ai-composer-history-thread {
    display: flex;
    flex-direction: column;
    gap: 0.45rem;
}
.ai-composer-history-card {
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
    background: #fff;
    border: 1px solid var(--border-color);
    border-radius: 8px;
    padding: 0.85rem 1rem;
    cursor: pointer;
    outline: none;
    transition: border-color 0.12s ease, box-shadow 0.12s ease, background 0.12s ease;
}
.ai-composer-history-card--refine {
    margin-left: 1.75rem;
    background: #fafafa;
    border-color: #ececec;
    position: relative;
}
.ai-composer-history-card--refine::before {
    content: "";
    position: absolute;
    left: -1rem;
    top: -0.45rem;
    bottom: 50%;
    width: 1rem;
    border-left: 2px solid var(--border-color);
    border-bottom: 2px solid var(--border-color);
    border-bottom-left-radius: 8px;
    pointer-events: none;
}
.ai-composer-history-card:hover {
    border-color: var(--primary-color);
    background: var(--primary-bg-light);
}
.ai-composer-history-card:focus-visible {
    border-color: var(--primary-color);
    box-shadow: 0 0 0 2px var(--primary-light);
}
.ai-composer-history-icon {
    flex: 0 0 auto;
    margin-top: 2px;
}
.ai-composer-history-body {
    flex: 1;
    min-width: 0;
}
.ai-composer-history-meta {
    font-size: 0.75rem;
    color: var(--text-muted);
    margin-bottom: 0.3rem;
}
.ai-composer-history-preview {
    font-size: 0.95rem;
    color: var(--text-color);
    line-height: 1.45;
    white-space: pre-wrap;
    word-break: break-word;
    display: -webkit-box;
    -webkit-line-clamp: 4;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.ai-composer-history-deflink {
    font-size: 0.78rem;
    color: var(--text-muted);
    font-style: italic;
    padding: 0.1rem 1rem 0;
}
.ai-composer-history-empty {
    padding: 1.5rem 0.5rem;
    color: var(--text-muted);
    font-size: 0.95rem;
    text-align: center;
}

/* ── OT slash-commands (/ot-…): inline result blocks + active-model chip ───────
   Rendered only on sysadmin surfaces that pass otCommands; inert elsewhere. */

/* Inline command result block (rendered into the transcript via appendBlock). */
.ai-ot-block {
    font-size: 0.9rem;
    color: var(--text-color);
}
.ai-ot-title {
    font-weight: 600;
    margin-bottom: 0.4rem;
}
.ai-ot-list {
    margin: 0;
    padding-left: 1.1rem;
}
.ai-ot-list li {
    margin: 0.15rem 0;
}
.ai-ot-block code {
    background: var(--primary-bg-light);
    border-radius: 4px;
    padding: 0.05rem 0.3rem;
}

/* /ot-model selector: one button per model, the active one checked. */
.ai-ot-models {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
}
.ai-ot-model {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    width: 100%;
    text-align: left;
    background: #fff;
    border: 1px solid var(--border-color);
    border-radius: 6px;
    padding: 0.4rem 0.6rem;
    cursor: pointer;
    font-size: 0.9rem;
    color: var(--text-color);
}
.ai-ot-model:hover {
    background: var(--primary-bg-light);
    border-color: var(--primary-color);
}
.ai-ot-model.is-active {
    border-color: var(--primary-color);
    background: var(--primary-light);
}
.ai-ot-model-check {
    width: 14px;
    height: 14px;
    flex: 0 0 14px;
    border-radius: 50%;
    border: 2px solid var(--border-color);
}
.ai-ot-model.is-active .ai-ot-model-check {
    border-color: var(--primary-color);
    background: var(--primary-color);
    box-shadow: inset 0 0 0 2px #fff;
}
.ai-ot-model-default {
    color: var(--text-muted);
    font-size: 0.78rem;
}
.ai-ot-note {
    margin-top: 0.4rem;
    color: var(--text-muted);
    font-size: 0.82rem;
}

/* Active-model chip, shown to the LEFT of the send button only when a non-default
   model is selected. */
.ai-composer-model-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.2rem;
    background: var(--primary-light);
    border: 1px solid var(--primary-color);
    border-radius: 999px;
    padding: 0 0.2rem 0 0.5rem;
    font-size: 0.78rem;
    color: var(--primary-hover);
    max-width: 11rem;
}
.ai-composer-model-chip-label {
    background: none;
    border: 0;
    padding: 0.15rem 0;
    cursor: pointer;
    color: inherit;
    font: inherit;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 9rem;
}
.ai-composer-model-chip-reset {
    background: none;
    border: 0;
    cursor: pointer;
    color: inherit;
    font-size: 1rem;
    line-height: 1;
    padding: 0 0.1rem;
}
.ai-composer-model-chip-reset:hover {
    color: var(--danger-color);
}

/* ── AI builder layout (Reports / Export) ────────────────────────────
   One modal, one DOM: the AI chat + chip-chain "data chain" on the left,
   a live-updating preview on the right with the action buttons in a header
   bar above it. The whole layout is built into the popupBox body (no
   subheader / footer). At ≥1024px the two panes sit side-by-side; below
   that the media query at the end of this block reflows them to a single
   stacked column. There is no JS layout branch — resizing just reflows.

   Desktop: give the popup a definite height (like the survey container) so
   the body is a defined-height flex child and each pane scrolls internally. */
.popupBox:has(.ai-builder-split) {
    height: 90vh;
    max-height: 90vh;
}
/* The split builder puts Save/Cancel (and the toolbar) in the right-pane preview
   header, so the popup's own footer is intentionally empty — hide it instead of
   showing a blank gray bar with a top border. */
.popupBox:has(.ai-builder-split) .popupBox-footer {
    display: none;
}
.ai-builder-split {
    display: flex;
    flex: 1 1 auto;
    min-height: 0;
    height: 100%;
}
/* Left pane: the chat transcript over the chip-chain summary, split 50/50 by
   default (each flex: 1 1 0). The column/row handles below let the user drag the
   boundaries — the divider lines live on the handles, not the pane edges. */
.ai-builder-pane-left {
    flex: 0 0 460px;
    display: flex;
    flex-direction: column;
    min-height: 0;
}
/* Transparent flex passthrough so the Core.aiChat widget's composer fills the
   chat area (mirrors .ai-assistant-panel .ai-chat-mount). */
.ai-builder-pane-left .ai-chat-mount,
.ai-builder-pane-left .ai-composer-composer {
    min-height: 0;
    display: flex;
    flex-direction: column;
}
.ai-builder-pane-left .ai-composer-composer {
    flex: 1 1 auto;
}
.ai-builder-pane-left .ai-chat-mount {
    flex: 1 1 0;
    padding: 0.75rem 1rem 0.5rem;
}
/* Input row + hint/buttons stay pinned below the scrolling transcript. */
.ai-builder-pane-left .ai-composer-input-row,
.ai-builder-pane-left .ai-composer-foot {
    flex-shrink: 0;
}
.ai-builder-pane-left .ai-builder-summary {
    flex: 1 1 0;
    min-height: 0;
    overflow-y: auto;
    padding: 0.5rem 1rem 0.75rem;
}
/* Resize handles. The column handle sits between the left pane and the preview;
   the row handle between the chat and the chip-chain. Both double as the visible
   divider line and brighten on hover/drag. */
.ai-builder-split-col,
.ai-builder-split-row {
    flex: 0 0 5px;
    background: var(--border-color);
    transition: background 0.15s ease;
}
.ai-builder-split-col {
    cursor: col-resize;
}
.ai-builder-split-row {
    cursor: row-resize;
}
.ai-builder-split-col:hover,
.ai-builder-split-col.dragging,
.ai-builder-split-row:hover,
.ai-builder-split-row.dragging {
    background: var(--primary-color);
}
/* Suppress text selection + force the resize cursor across the whole document
   while a handle is being dragged. */
body.ai-builder-resizing {
    user-select: none;
    cursor: col-resize;
}
/* Right pane: header toolbar (pinned) over the scrolling preview body. The
   min-width:0 lets a wide preview (e.g. a many-column export table) be clamped
   to the pane and scroll horizontally inside it, rather than expanding the pane
   and forcing the whole modal/screen to scroll. */
.ai-builder-pane-right {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    min-height: 0;
    min-width: 0;
}
.ai-builder-preview-header {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.6rem 1rem;
    border-bottom: 1px solid var(--border-color);
    background: #f8f9fa;
    flex-shrink: 0;
}
/* Pushes the right-aligned actions (Save / Cancel) away from the left
   group (hamburger / Refresh / PDF|Download). */
.ai-builder-preview-header-spacer {
    flex: 1 1 auto;
}
.ai-builder-preview-body {
    flex: 1 1 auto;
    overflow: auto;
    padding: 0.75rem 1rem;
    min-height: 0;
    min-width: 0;
}
/* Placeholder / loading / error states shown before a preview renders. */
.ai-builder-preview-empty {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
    min-height: 200px;
    color: var(--text-muted);
    font-size: 0.9rem;
    text-align: center;
    padding: 1rem;
}

/* Narrow viewports: reflow the two panes into a single stacked column —
   chat, chip-chain, then the toolbar + preview below. The popup sizes to
   content (scrolling as a whole) instead of pinning to 90vh, and the chat
   gets a usable fixed height so its transcript still scrolls internally.
   On phones (≤768px) popupBox goes fullscreen, which keeps this column
   layout but lets the popup own its own height. */
@media (max-width: 1023px) {
    .popupBox:has(.ai-builder-split) {
        height: auto;
        max-height: 95vh;
    }
    .ai-builder-split {
        flex-direction: column;
        height: auto;
    }
    .ai-builder-pane-left {
        flex: 0 0 auto;
        border-bottom: 1px solid var(--border-color);
    }
    /* Stacked column: each panel uses an explicit/content height (no flex
       distribution), and the drag handles are inert, so hide them. */
    .ai-builder-pane-left .ai-chat-mount {
        flex: 0 0 auto;
        height: 45vh;
    }
    .ai-builder-pane-left .ai-builder-summary {
        flex: 0 0 auto;
        max-height: 30vh;
        border-top: 1px solid var(--border-color);
    }
    .ai-builder-split-col,
    .ai-builder-split-row {
        display: none;
    }
    .ai-builder-pane-right {
        flex: 0 0 auto;
    }
    .ai-builder-preview-body {
        overflow: visible;
    }
}
