/* -- Layout hard-lock -- */
html,body{margin:0;padding:0;width:100vw;height:100dvh;overflow:hidden;}
.app-shell{display:flex;width:100vw;max-width:100vw;height:100dvh;overflow:hidden;}
.app-sidebar{width:var(--sidebar-width,260px);min-width:180px;max-width:480px;flex-shrink:0;display:flex;flex-direction:column;height:100dvh;overflow:hidden;position:relative;}
.app-sidebar.resizing{transition:none!important;}
.app-main{flex:1 1 auto;min-width:0;max-width:calc(100vw - var(--sidebar-width,260px));display:flex;flex-direction:column;height:100dvh;overflow:hidden;}
.sidebar-resize-handle{position:absolute;top:0;right:-3px;width:6px;height:100%;cursor:col-resize;z-index:60;background:transparent;}
.sidebar-resize-handle:hover,.sidebar-resize-handle.active{background:var(--primary);opacity:.4;}
/* overflow-anchor:auto (browser default) keeps the view stable while reading when
   async content above (images/code/math/mermaid) finishes rendering and changes
   height — preventing the "jump to another response" while scrolling. During an
   active stream we disable it (.is-streaming) so the JS bottom-pin owns scrolling. */
.chat-messages{flex:1 1 0%;min-height:0;overflow-x:hidden!important;overflow-y:auto;overflow-anchor:auto;overscroll-behavior-y:contain;
  scrollbar-width:thin;scrollbar-color:color-mix(in srgb, var(--primary) 55%, transparent) transparent;}
.chat-messages.is-streaming{overflow-anchor:none;}
/* Primary-colored scrollbar thumb (Firefox above; WebKit/Chromium/Safari below)
   so the scrollbar is clearly visible against the message list, instead of the
   near-invisible default gray/secondary track. */
.chat-messages::-webkit-scrollbar{width:9px;}
.chat-messages::-webkit-scrollbar-track{background:transparent;}
.chat-messages::-webkit-scrollbar-thumb{background:color-mix(in srgb, var(--primary) 55%, transparent);border-radius:99px;border:2px solid transparent;background-clip:padding-box;}
.chat-messages::-webkit-scrollbar-thumb:hover{background:var(--primary);border:2px solid transparent;background-clip:padding-box;}
/* One-tick instant-jump helper (used by scrollToAiMessage on mobile). */
.chat-messages.scroll-instant{scroll-behavior:auto!important;}
/* Floating "Scroll to bottom" pill — fixed, centred inside the chat column
   (not the full viewport) by offsetting left by half the sidebar width */
#scroll-to-bottom-btn{
  position:fixed;
  left:calc(var(--sidebar-width,260px) + (100vw - var(--sidebar-width,260px)) / 2);
  transform:translateX(-50%);
  bottom:120px; /* fallback; JS overrides on desktop to sit above the composer */
  display:none;align-items:center;gap:6px;
  padding:7px 16px;border-radius:999px;
  background:var(--surface);border:1px solid var(--border);
  color:var(--text);font-size:.78rem;font-weight:600;
  box-shadow:0 4px 16px rgba(0,0,0,.15);cursor:pointer;
  white-space:nowrap;z-index:50;
  pointer-events:auto;
}
#scroll-to-bottom-btn:hover{background:var(--bg);border-color:var(--primary);color:var(--primary);}
#scroll-to-bottom-btn.visible{display:flex;}
#scroll-to-bottom-btn svg{flex-shrink:0;}
/* On mobile — centre in full viewport (sidebar is hidden) */
@media(max-width:768px){
  #scroll-to-bottom-btn{left:50%;transform:translateX(-50%);}
}
/* Sidebar collapsed on desktop — centre in full viewport */
.app-shell.sidebar-collapsed #scroll-to-bottom-btn{left:50%;transform:translateX(-50%);}
/* ── Model usage note (per-model chat instructions) ────────────────────── */
.model-usage-note{display:flex;align-items:flex-start;gap:8px;padding:8px 10px;margin:0 0 8px;
  border-radius:10px;background:color-mix(in srgb, var(--accent, #6366f1) 10%, transparent);
  border:1px solid color-mix(in srgb, var(--accent, #6366f1) 25%, transparent);
  font-size:.82rem;line-height:1.4;color:var(--text)}
.model-usage-note-icon{flex-shrink:0;margin-top:1px}
.model-usage-note-text{flex:1;min-width:0;word-wrap:break-word}
.model-usage-note-text b,.model-usage-note-text strong{font-weight:600}
.model-usage-note-close{flex-shrink:0;background:none;border:none;color:var(--muted);cursor:pointer;
  font-size:.85rem;line-height:1;padding:2px 4px;border-radius:4px}
.model-usage-note-close:hover{background:color-mix(in srgb, var(--text) 10%, transparent);color:var(--text)}
/* ── Draw mode (inline image generation) ───────────────────────────────── */
/* draw-mode-bar sits inside .composer-toolbar as a flex sibling to composer-tools-left */
.draw-mode-bar{display:none;align-items:center;gap:6px;padding:0;flex:1;min-width:0;flex-wrap:nowrap;overflow-x:hidden}
/* Scoped by ID, not class — #video-mode-bar also carries the draw-mode-bar
   class (for shared styling) but must NOT reveal when draw-mode is active. */
.composer-card.draw-mode #draw-mode-bar{display:flex}
/* hide the text tools + model pill when draw mode is active */
.composer-card.draw-mode .composer-tools-left{display:none!important}
.draw-mode-mobile-header{display:none}
.draw-mode-icon{font-size:.95rem;flex-shrink:0}
/* ── Video mode (inline video generation) — reuses draw-mode-bar's inner
   element classes for visual consistency; only the container visibility is
   scoped separately by ID so draw mode and video mode never show at once. */
.composer-card.video-mode #video-mode-bar{display:flex}
.composer-card.video-mode .composer-tools-left{display:none!important}
.composer-card.video-mode{border-color:color-mix(in srgb,var(--primary) 40%,transparent)!important}
#video-gen-btn.draw-active{color:var(--primary)!important;background:color-mix(in srgb,var(--primary) 10%,transparent)!important}
.composer-card.video-mode #video-error-bar.visible{display:block}
/* ── Audio mode (inline text-to-speech) — reuses draw-mode-bar's inner
   element classes for visual consistency; only the container visibility is
   scoped separately by ID so draw/video/audio mode never show at once. */
.composer-card.audio-mode #audio-mode-bar{display:flex}
.composer-card.audio-mode .composer-tools-left{display:none!important}
.composer-card.audio-mode{border-color:color-mix(in srgb,var(--primary) 40%,transparent)!important}
#audio-gen-btn.draw-active{color:var(--primary)!important;background:color-mix(in srgb,var(--primary) 10%,transparent)!important}
.composer-card.audio-mode #audio-error-bar.visible{display:block}

/* ── Model pill: matches composer-model-pill exactly (shared by Draw/Video/
   Audio via this one class, so all three stay in sync automatically) ── */
.draw-model-pill{
  display:flex;align-items:center;justify-content:flex-start;gap:7px;padding:4px 10px;
  background:color-mix(in srgb,var(--primary) 8%,transparent);
  border:1px solid color-mix(in srgb,var(--primary) 20%,transparent);
  border-radius:8px;cursor:pointer;font-size:.8rem;font-weight:700;line-height:1;
  color:var(--primary);white-space:nowrap;font-family:inherit;text-align:left;
  transition:background .18s,border-color .18s;flex-shrink:0}
.draw-model-pill span{text-align:left}
.draw-model-pill:hover{
  background:color-mix(in srgb,var(--primary) 15%,transparent);
  border-color:color-mix(in srgb,var(--primary) 35%,transparent)}
.draw-model-pill svg{color:var(--primary);flex-shrink:0}

/* ── Tool buttons: font/color now matches text mode's icon buttons exactly —
   .composer-tool-btn (desktop Tools popover) and .mts-action-btn (mobile "+"
   sheet) both use font-size .72rem/weight 600, a full-strength label color
   (var(--text) — was var(--muted), reading dim/washed-out next to text
   mode), and a separately muted icon (var(--muted), below) so the icon and
   label read as two intentional tones instead of one flat gray. ── */
.draw-size-pill,.draw-count-pill,.draw-ref-btn,.draw-enhance-btn,.draw-advanced-toggle,.draw-more-btn{
  display:flex;align-items:center;gap:5px;padding:5px 9px;
  background:var(--surface);border:1px solid var(--border);border-radius:9px;cursor:pointer;
  font-size:.72rem;font-weight:600;color:var(--text);white-space:nowrap;line-height:1;
  font-family:inherit;transition:background .15s,color .15s,border-color .15s;flex-shrink:0}
.draw-size-pill svg,.draw-count-pill svg,.draw-ref-btn svg,.draw-enhance-btn svg,
.draw-advanced-toggle svg,.draw-more-btn svg{color:var(--muted);transition:color .15s}
.draw-size-pill:hover,.draw-count-pill:hover,.draw-ref-btn:hover:not([disabled]),
.draw-enhance-btn:hover:not([disabled]),.draw-advanced-toggle:hover,.draw-more-btn:hover{
  background:color-mix(in srgb,var(--primary) 10%,transparent);
  border-color:color-mix(in srgb,var(--primary) 30%,transparent);color:var(--primary)}
.draw-size-pill:hover svg,.draw-count-pill:hover svg,.draw-ref-btn:hover:not([disabled]) svg,
.draw-enhance-btn:hover:not([disabled]) svg,.draw-advanced-toggle:hover svg,.draw-more-btn:hover svg{color:var(--primary)}
/* Active / selected state */
.draw-ref-btn.has-ref,.draw-advanced-toggle.has-value{
  color:var(--primary);background:color-mix(in srgb,var(--primary) 10%,transparent);
  border-color:color-mix(in srgb,var(--primary) 30%,transparent)}
.draw-ref-btn.has-ref svg,.draw-advanced-toggle.has-value svg{color:var(--primary)}
.draw-ref-btn.has-ref:hover:not([disabled]),.draw-advanced-toggle.has-value:hover{
  background:color-mix(in srgb,var(--primary) 14%,transparent);
  border-color:color-mix(in srgb,var(--primary) 40%,transparent)}
/* More button: open state tints primary */
.draw-more-btn{position:relative}
.draw-more-btn.active{color:var(--primary)}
.draw-more-chevron{transition:transform .2s ease}
.draw-more-btn.active .draw-more-chevron{transform:rotate(180deg)}
/* Active-options dot when count≠1 or a negative prompt is set */
.draw-more-btn.has-active::after{content:'';position:absolute;top:2px;right:2px;width:5px;height:5px;
  border-radius:50%;background:var(--primary);border:1.5px solid var(--surface);pointer-events:none}
/* Floating popup (desktop) — positioned above the More button via JS */
.draw-more-extra{display:none;position:fixed;z-index:1000;background:var(--surface);
  border:1px solid var(--border);border-radius:14px;padding:8px;
  box-shadow:0 -2px 24px rgba(0,0,0,.12),0 4px 12px rgba(0,0,0,.06);
  flex-direction:column;gap:8px;min-width:190px;max-width:calc(100vw - 16px)}
.draw-more-extra.open{display:flex;animation:toolPopIn .15s cubic-bezier(.22,1,.36,1)}
/* Match the Tools popover's row typography exactly (same font-size/weight/
   letter-spacing as .tool-label) so Draw and Video "More" popovers look
   consistent with Tools rather than using their own slightly-different sizing. */
.draw-more-extra .draw-model-pill span,.draw-more-extra .draw-size-pill span,
.draw-more-extra .draw-count-pill span,.draw-more-extra .draw-ref-btn span,
.draw-more-extra .draw-enhance-btn,.draw-more-extra .draw-advanced-toggle,
.draw-more-extra .draw-mob-label{
  font-size:.72rem!important;font-weight:600!important;letter-spacing:.01em!important}
.draw-more-extra .draw-size-strip{display:block;width:100%}
.draw-more-extra .draw-size-pill,.draw-more-extra .draw-count-pill,
.draw-more-extra .draw-enhance-btn,.draw-more-extra .draw-neg-wrap,
.draw-more-extra .draw-advanced-toggle{
  width:100%;box-sizing:border-box;justify-content:flex-start}
.draw-more-extra .draw-size-pill>span,.draw-more-extra .draw-count-pill>span{flex:1 1 auto;text-align:left}
.draw-more-extra .draw-size-pill>svg:nth-of-type(2),.draw-more-extra .draw-count-pill>svg:nth-of-type(2){margin-left:auto}
/* ── Draw & Video modes (not Audio, which keeps the "More" popup): the
   size/qty/enhance/negative/extra controls that used to hide behind the
   "More" chevron are always-visible icon buttons in the main row, right
   after the attachment button — order: Model, Attachment, Size/Duration/
   Resolution/Aspect, Enhance, Negative/Audio, Extra. Scoped by #draw-mode-bar
   / #video-mode-bar id so Audio (which reuses the same draw-more-btn/
   draw-more-extra classes) is unaffected.
   Wrapped in min-width:769px — earlier this was unscoped and, because
   descendant ID selectors outrank the mobile sheet's plain-class rules, it
   was silently overriding the mobile "Auto" size pill's width:100% down to
   content-width even though it only ever visually applied on desktop. */
.draw-btn-label{display:none}
@media(min-width:769px){
  #draw-mode-bar #draw-more-btn,#video-mode-bar #video-more-btn{display:none}
  #draw-mode-bar #draw-more-extra,#video-mode-bar #video-more-extra{display:contents}
  #draw-mode-bar #draw-more-extra .draw-size-strip{display:flex;width:auto}
  #draw-mode-bar #draw-more-extra .draw-size-pill,
  #draw-mode-bar #draw-more-extra .draw-count-pill,
  #draw-mode-bar #draw-more-extra .draw-neg-wrap,
  #video-mode-bar #video-more-extra .draw-count-pill{
    width:auto;box-sizing:content-box}
  /* Enhance/Negative/Audio deliberately excluded above — they get fixed 40x40
     square sizing below, which a width:auto here would (via higher selector
     specificity, 3 ancestors deep) otherwise silently override. */
  /* Size ("Auto") / Qty ("1") — and video's Duration/Resolution/Aspect, which
     share the same .draw-count-pill markup — icon only on desktop, matching
     the other icon-only 40x40 buttons in this row. Mobile keeps its label
     text; this is desktop-only. */
  #draw-mode-bar #draw-more-extra .draw-size-pill>span,
  #draw-mode-bar #draw-more-extra .draw-count-pill>span,
  #video-mode-bar #video-more-extra .draw-count-pill>span,
  #draw-mode-bar #draw-more-extra .draw-size-pill>svg:nth-of-type(2),
  #draw-mode-bar #draw-more-extra .draw-count-pill>svg:nth-of-type(2),
  #video-mode-bar #video-more-extra .draw-count-pill>svg:nth-of-type(2){display:none!important}
  #draw-mode-bar #draw-more-extra .draw-size-pill,
  #draw-mode-bar #draw-more-extra .draw-count-pill,
  #video-mode-bar #video-more-extra .draw-count-pill{
    width:40px!important;height:40px!important;min-width:40px!important;
    padding:0!important;justify-content:center;border-radius:10px!important}
  /* Match the attachment button's 40x40 square exactly (it was the only icon-only
     button with real sizing before — these toggle buttons had none, so they sat
     visibly smaller than the other pills/squares in the row). */
  #draw-mode-bar #draw-enhance-btn,#draw-mode-bar #draw-advanced-toggle,#draw-mode-bar #draw-extra-toggle,
  #video-mode-bar #video-enhance-btn,#video-mode-bar #video-audio-toggle,#video-mode-bar #video-extra-toggle{
    width:40px;min-width:40px;height:40px;padding:0!important;justify-content:center;border-radius:10px!important}
  /* Enhance's star and Negative's circle-slash kept their small inline 11-12px
     icon size (only the attachment/extra icons had a CSS rule bumping them up
     to 16-18px), so next to the newly-square buttons they read as thin/faint.
     Match Extra's 16px so all four icon-only buttons look consistently bold. */
  #draw-mode-bar #draw-enhance-btn svg,#draw-mode-bar #draw-advanced-toggle svg,
  #video-mode-bar #video-enhance-btn svg,#video-mode-bar #video-audio-toggle svg{
    width:16px;height:16px}
  /* Row can now hold more controls than before — scroll horizontally instead
     of clipping if a narrow desktop window can't fit them all. */
  #draw-mode-bar,#video-mode-bar{overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none}
  #draw-mode-bar::-webkit-scrollbar,#video-mode-bar::-webkit-scrollbar{display:none}
  /* .draw-ref-preview-row sits after Extra in the markup (so it naturally
     lands below the whole tile strip on mobile — see its own comment), but
     on desktop everything in #draw-mode-bar/#video-mode-bar flattens into
     one flex row via display:contents, so without help it would show up at
     the very end next to Exit instead of by the attachment button. order
     pulls it (and its two neighbours) back to the front, right after
     Reference, without needing to touch every other tile's order. */
  #draw-mode-bar .draw-mode-icon,#video-mode-bar .draw-mode-icon{order:-4}
  #draw-mode-bar #draw-model-pill,#video-mode-bar #video-model-pill{order:-3}
  #draw-mode-bar #draw-ref-wrap,#video-mode-bar #video-ref-wrap{order:-2}
  #draw-mode-bar #draw-ref-preview-row,#video-mode-bar #video-ref-preview-row{order:-1}
  /* Model pill: desktop has plenty of icon-only buttons crowding the row now,
     so trim its max-width a bit from the shared 220px/180px (mobile keeps
     the full width — this is desktop-only). */
  #draw-mode-bar #draw-model-pill,#video-mode-bar #video-model-pill{max-width:160px}
  #draw-mode-bar #draw-model-pill span,#video-mode-bar #video-model-pill span{max-width:120px}
}
.draw-model-pill{position:relative;max-width:220px;overflow:hidden}
.draw-model-pill span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:180px}
.draw-size-strip{display:flex;align-items:center;flex-shrink:0}
.draw-size-pill{position:relative}
.draw-size-pill span{pointer-events:none}
.draw-size-select{position:absolute;inset:0;opacity:0;cursor:pointer;width:100%;height:100%}
.draw-ref{display:flex;align-items:center;gap:6px;flex-shrink:0}
.draw-ref-btn[disabled]{opacity:.35;cursor:not-allowed}
.draw-ref-btn[disabled]:hover{background:none;color:var(--muted)}
.draw-ref-chip{position:relative;width:30px;height:30px;border-radius:7px;overflow:hidden;border:1.5px solid var(--primary);flex-shrink:0}
.draw-ref-chip img{width:100%;height:100%;object-fit:cover;display:block}
.draw-ref-remove{position:absolute;top:-1px;right:-1px;background:rgba(0,0,0,.6);color:#fff;border:none;border-radius:0 6px 0 6px;cursor:pointer;font-size:.6rem;line-height:1;padding:2px 4px}
.draw-ref-chip-label{position:absolute;bottom:0;left:0;right:0;background:rgba(0,0,0,.6);color:#fff;font-size:.5rem;font-weight:600;text-align:center;line-height:1.3;pointer-events:none}
.draw-ref-extra-chips{display:flex;align-items:center;gap:4px;flex-shrink:0}
.draw-count-pill{position:relative;flex-shrink:0}
.draw-count-pill span{pointer-events:none}
.draw-count-select{position:absolute;inset:0;opacity:0;cursor:pointer;width:100%;height:100%}
.img-action-btn.use-as-ref{color:var(--primary);border-color:color-mix(in srgb,var(--primary) 30%,transparent);background:color-mix(in srgb,var(--primary) 6%,transparent)}
.draw-enhance-btn{flex-shrink:0}
.draw-enhance-btn[disabled]{opacity:.5;cursor:not-allowed}
.draw-neg-wrap{position:relative;flex-shrink:0;display:flex;align-items:center}
.draw-advanced-toggle{flex-shrink:0}
/* Positioned via JS (position:fixed) so it escapes the draw bar's overflow:hidden. */
.draw-neg-popover{position:fixed;z-index:1000;width:300px;max-width:calc(100vw - 24px);background:var(--bg);border:1.5px solid var(--border);border-radius:12px;box-shadow:0 8px 28px rgba(0,0,0,.22);padding:12px;display:none;flex-direction:column;gap:8px}
.draw-neg-popover.visible{display:flex}
.draw-neg-pop-head{display:flex;align-items:center;justify-content:space-between;font-size:.78rem;font-weight:700;color:var(--text)}
.draw-neg-pop-close{background:none;border:none;cursor:pointer;color:var(--muted);font-size:.9rem;line-height:1;padding:2px 5px;border-radius:5px}
.draw-neg-pop-close:hover{color:var(--text);background:var(--surface)}
.draw-neg-input{background:var(--surface);border:1.5px solid var(--border);border-radius:8px;padding:7px 10px;font-size:.8rem;color:var(--text);font-family:inherit;width:100%;box-sizing:border-box}
.draw-neg-input:focus{outline:none;border-color:var(--primary)}
.draw-neg-pop-hint{font-size:.7rem;color:var(--muted);line-height:1.4}
.draw-neg-pop-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:2px}
.draw-neg-pop-btn{padding:5px 13px;border-radius:7px;border:1.5px solid var(--border);background:var(--surface);color:var(--text);font-size:.74rem;font-weight:600;cursor:pointer;font-family:inherit}
.draw-neg-pop-btn:hover{border-color:var(--primary);color:var(--primary)}
.draw-neg-pop-btn.primary{background:var(--primary);border-color:var(--primary);color:#fff}
.draw-neg-pop-btn.primary:hover{filter:brightness(1.05);color:#fff}
/* ── Extra options button + popover ─────────────────────────────────────────── */
.draw-extra-wrap{position:relative;flex-shrink:0;display:flex;align-items:center}
.draw-extra-toggle{flex-shrink:0;background:var(--surface);border:1px solid var(--border);border-radius:9px;
  display:flex;align-items:center;gap:5px;padding:5px 9px;cursor:pointer;
  font-size:.72rem;font-weight:600;color:var(--text);white-space:nowrap;font-family:inherit;
  transition:background .15s,color .15s,border-color .15s}
.draw-extra-toggle svg{color:var(--muted);transition:color .15s}
.draw-extra-toggle:hover{background:color-mix(in srgb,var(--primary) 10%,transparent);
  border-color:color-mix(in srgb,var(--primary) 30%,transparent);color:var(--primary)}
.draw-extra-toggle:hover svg{color:var(--primary)}
.draw-extra-toggle.has-value{color:var(--primary);background:color-mix(in srgb,var(--primary) 10%,transparent);
  border-color:color-mix(in srgb,var(--primary) 30%,transparent)}
.draw-extra-toggle.has-value svg{color:var(--primary)}
.draw-extra-toggle.has-value:hover{background:color-mix(in srgb,var(--primary) 14%,transparent);
  border-color:color-mix(in srgb,var(--primary) 40%,transparent)}
.draw-extra-popover{position:fixed;z-index:1001;width:340px;max-width:calc(100vw - 24px);
  max-height:min(420px,calc(100vh - 24px));overflow-y:auto;
  background:var(--bg);border:1.5px solid var(--border);border-radius:12px;
  box-shadow:0 8px 28px rgba(0,0,0,.22);padding:12px;display:none;flex-direction:column;gap:10px}
.draw-extra-popover.visible{display:flex}
.draw-extra-pop-head{display:flex;align-items:center;justify-content:space-between;font-size:.78rem;font-weight:700;color:var(--text)}
.draw-extra-pop-close{background:none;border:none;cursor:pointer;color:var(--muted);font-size:.9rem;line-height:1;padding:2px 5px;border-radius:5px}
.draw-extra-pop-close:hover{color:var(--text);background:var(--surface)}
.draw-extra-chips{display:flex;flex-wrap:wrap;gap:5px}
.draw-extra-chip{display:inline-flex;align-items:center;gap:4px;padding:3px 9px;
  border-radius:99px;border:1.5px solid var(--border);background:var(--surface);
  color:var(--text);font-size:.72rem;font-weight:600;cursor:pointer;font-family:inherit;
  transition:border-color .15s,background .15s,color .15s}
.draw-extra-chip:hover{border-color:var(--primary);color:var(--primary);background:color-mix(in srgb,var(--primary) 8%,transparent)}
.draw-extra-no-chips{font-size:.74rem;color:var(--muted);font-style:italic}
/* ── Pruna p-image/p-image-edit size control (required Aspect dropdown +
   optional width/height) — reuses .draw-extra-popover for the shell so it
   looks native to the rest of Draw mode's popovers. */
.draw-pruna-aspect-select{width:100%;box-sizing:border-box;background:var(--surface);
  border:1.5px solid var(--border);border-radius:8px;padding:7px 8px;font-size:.82rem;
  color:var(--text);font-family:inherit;cursor:pointer}
.draw-pruna-aspect-select:focus{outline:none;border-color:var(--primary)}
/* p-image-edit's inline aspect control reuses .draw-size-pill/.draw-size-select
   verbatim (see _drawBuildPrunaSizeControl) so no dedicated CSS is needed here. */
.draw-pruna-size-wh{display:flex;align-items:flex-end;gap:8px}
.draw-pruna-size-wh>div{flex:1}
.draw-pruna-size-wh label{display:block;font-size:.68rem;color:var(--muted);margin-bottom:3px}
.draw-pruna-size-wh input{width:100%;box-sizing:border-box;background:var(--surface);
  border:1.5px solid var(--border);border-radius:8px;padding:6px 8px;font-size:.8rem;
  color:var(--text);font-family:inherit}
.draw-pruna-size-wh input:focus{outline:none;border-color:var(--primary)}
.draw-pruna-size-set{width:100%;box-sizing:border-box;text-align:center;margin:2px 0 4px}
.draw-pruna-size-ratio-label{font-size:.72rem;color:var(--muted)}
/* Centered modal, not a pill-anchored popover — the trigger pill can live in
   the desktop toolbar, the collapsed "More" popup, or the mobile sheet, each
   with different transforms/overflow; a fixed, viewport-centered modal has
   no anchor point to miscalculate regardless of which one it opens from. */
.draw-pruna-size-backdrop{display:none;position:fixed;inset:0;z-index:2000;
  background:rgba(0,0,0,.35);align-items:center;justify-content:center;padding:16px;box-sizing:border-box}
.draw-pruna-size-backdrop.visible{display:flex}
.draw-pruna-size-card{position:static;display:flex;width:340px;max-width:100%}
.draw-extra-rows{display:flex;flex-direction:column;gap:6px}
.draw-extra-row{display:flex;align-items:center;gap:5px}
.draw-extra-key,.draw-extra-val{
  background:var(--surface)!important;border:1.5px solid var(--border)!important;border-radius:7px!important;
  padding:5px 8px!important;font-size:.78rem!important;color:var(--text)!important;
  font-family:inherit!important;transition:border-color .15s!important;box-sizing:border-box!important}
.draw-extra-key{flex:1 1 50%!important;width:0!important;min-width:0!important}
.draw-extra-key[readonly]{background:color-mix(in srgb,var(--primary) 6%,transparent)!important;color:var(--primary)!important;border-color:color-mix(in srgb,var(--primary) 25%,transparent)!important}
.draw-extra-val{flex:1 1 50%!important;width:0!important;min-width:0!important}
.draw-extra-key:focus,.draw-extra-val:focus{outline:none!important;border-color:var(--primary)!important}
.draw-extra-rm{background:none;border:none;cursor:pointer;color:var(--muted);padding:3px 5px;border-radius:5px;font-size:.85rem;line-height:1;flex-shrink:0}
.draw-extra-rm:hover{color:#e53e3e;background:rgba(229,62,62,.1)}
.draw-extra-add-btn{align-self:flex-start;display:inline-flex;align-items:center;gap:4px;
  padding:4px 10px;border-radius:7px;border:1.5px dashed var(--border);
  background:none;color:var(--muted);font-size:.74rem;font-weight:600;cursor:pointer;font-family:inherit}
.draw-extra-add-btn:hover{border-color:var(--primary);color:var(--primary)}
.draw-extra-hint{font-size:.7rem;color:var(--muted);line-height:1.4}
.draw-extra-pop-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:2px}
.draw-extra-pop-btn{padding:5px 13px;border-radius:7px;border:1.5px solid var(--border);background:var(--surface);color:var(--text);font-size:.74rem;font-weight:600;cursor:pointer;font-family:inherit}
.draw-extra-pop-btn:hover{border-color:var(--primary);color:var(--primary)}
.draw-extra-pop-btn.primary{background:var(--primary);border-color:var(--primary);color:#fff}
.draw-extra-pop-btn.primary:hover{filter:brightness(1.05);color:#fff}
.img-applied-params{font-size:.68rem;color:var(--muted);margin-top:4px;line-height:1.4}
.img-applied-params .applied{color:var(--primary);font-weight:600}
.draw-exit-btn{display:inline-flex;align-items:center;gap:5px;background:var(--surface);border:1px solid var(--border);cursor:pointer;color:var(--muted);padding:5px 9px;border-radius:9px;font-size:.78rem;font-weight:500;font-family:inherit;line-height:1;flex-shrink:0;transition:background .15s,color .15s,border-color .15s}
.draw-exit-btn:hover{background:color-mix(in srgb,var(--primary) 10%,transparent);border-color:color-mix(in srgb,var(--primary) 30%,transparent);color:var(--primary)}
.draw-error-bar{display:none;padding:5px 10px;font-size:.78rem;color:#dc2626;background:rgba(239,68,68,.08);border-top:1px solid rgba(239,68,68,.2)}
.composer-card.draw-mode #draw-error-bar.visible{display:block}
.composer-card.draw-mode{border-color:color-mix(in srgb,var(--primary) 40%,transparent)!important}
#img-gen-btn.draw-active{color:var(--primary)!important;background:color-mix(in srgb,var(--primary) 10%,transparent)!important}
#web-search-btn.tool-active,#reasoning-btn.tool-active,#docgen-btn.tool-active,#deep-research-btn.tool-active{color:var(--primary)!important;background:color-mix(in srgb,var(--primary) 12%,transparent)!important}
/* draw-mode-bar-body: desktop = display:contents so children flow directly in the bar */
.draw-mode-bar-body{display:contents}
/* Mobile-only grouping wrapper (Size+Qty / Duration+Resolution+Aspect side by
   side) — display:contents on desktop so it's invisible to the flattening
   chain above and the pills flow into the row exactly as before. */
.draw-mob-row,.draw-mob-col{display:contents}
/* Mobile-sheet-only chrome — hidden on desktop */
#draw-sheet-backdrop{display:none}
.draw-sheet-handle-row,.draw-sheet-footer,.draw-mob-label,.draw-active-strip{display:none}
@media(max-width:768px){
  /* On mobile the draw options appear as a bottom-sheet popup styled to match the
     "+" composer tool sheet (#mobile-tool-sheet) — sectioned, full-width controls. */
  #draw-sheet-backdrop,#video-sheet-backdrop,#audio-sheet-backdrop{
    display:block;position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,.42);
    -webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);
    z-index:899;opacity:0;pointer-events:none;transition:opacity .3s ease;
  }
  #draw-sheet-backdrop.open,#video-sheet-backdrop.open,#audio-sheet-backdrop.open{opacity:1;pointer-events:auto}

  /* The bar becomes the sheet (display:flex only while draw mode is active).
     Scoped by ID — #video-mode-bar shares this class for styling only. */
  .composer-card.draw-mode #draw-mode-bar{
    position:fixed;left:0;right:0;bottom:0;z-index:900;
    flex-direction:column;align-items:stretch;gap:0;
    background:var(--surface);border-top:1px solid var(--border);
    border-radius:20px 20px 0 0;box-shadow:0 -8px 40px rgba(0,0,0,.18);
    max-height:80vh;overflow-y:auto;-webkit-overflow-scrolling:touch;
    padding:0;padding-bottom:calc(env(safe-area-inset-bottom,0px) + 8px);
    transform:translateY(100%);
    transition:transform .3s cubic-bezier(.16,1,.3,1);
  }
  .composer-card.draw-mode #draw-mode-bar.draw-sheet-open{transform:translateY(0)}

  /* Handle */
  .draw-sheet-handle-row{display:flex;justify-content:center;padding:10px 0 4px}
  .draw-sheet-handle{width:36px;height:4px;border-radius:2px;background:var(--border)}
  /* Header */
  .draw-mode-mobile-header{display:flex;align-items:center;justify-content:space-between;padding:2px 16px 10px}
  .draw-mode-mobile-title{font-size:.88rem;font-weight:700;color:var(--text);letter-spacing:-.01em;display:flex;align-items:center;gap:6px}
  .draw-mode-mobile-close{display:flex!important;align-items:center;justify-content:center;width:28px;height:28px;padding:0;border-radius:8px;border:1px solid var(--border);background:var(--bg);color:var(--muted);cursor:pointer;-webkit-tap-highlight-color:transparent;transition:background .15s}
  .draw-mode-mobile-close:active{background:var(--border)}
  .draw-mode-icon{display:none}
  .draw-exit-btn:not(.draw-mode-mobile-close){display:none}

  /* Body — sectioned like .mts-body */
  .draw-mode-bar-body{display:flex;flex-direction:column;align-items:stretch;gap:0;padding:0 14px 6px}
  .draw-mob-label{display:block;font-size:.68rem;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.07em;margin:14px 0 7px}
  /* The very first label ("Model") immediately follows .draw-mode-icon, which
     is display:none on mobile but still occupies its DOM slot — so the 14px
     top margin above still lands, opening an extra gap under the sheet's
     header that text mode's Compose Options sheet doesn't have. Collapse
     just that one instance; every other label keeps its normal 14px gap. */
  .draw-mode-icon+.draw-mob-label{margin-top:0}
  /* Size+Qty (draw) / Duration+Resolution+Aspect (video) side by side instead of
     each on its own full-width row — cuts the sheet's height noticeably. Wraps
     to a second line on very narrow phones since each column has a min-width. */
  .draw-mob-row{display:flex;flex-wrap:wrap;gap:8px;width:100%}
  .draw-mob-col{display:flex;flex-direction:column;flex:1 1 110px;min-width:0}
  .draw-mob-col .draw-mob-label{margin:14px 0 7px}
  .draw-mob-col .draw-size-pill,.draw-mob-col .draw-count-pill{width:100%}
  /* Tile row — Reference/Size/Qty/Enhance/Negative/Extra (draw), Reference/
     Duration/Resolution/Aspect/Enhance/Audio/Extra (video), Voice/Format
     (audio) all sit as 68px-wide, auto-height icon-over-label tiles under one
     "Options" heading — sized to exactly match .mts-action-btn (the text-mode
     Tools grid: flex:0 0 68px, no fixed height) instead of stacked/stretched
     full-width rows. Height was previously forced to a fixed 68px here too,
     making these noticeably taller/squarer than the actual text-mode tiles
     (whose height is just padding+icon+label, ~58px) — auto now matches.
     !important is needed to outrank the unscoped desktop pill rules
     (height/padding) that would otherwise still apply here since they're not
     media-scoped. */
  /* Slideable strip instead of wrapping to a second line — swipe to see the
     rest, same pattern as .mts-actions in the text-mode Tools grid. Always
     left-aligned (unlike .mts-actions, which centers when it fits) and
     flush with the "Options" label above it — no edge bleed. */
  .draw-tile-row{align-items:flex-start;flex-wrap:nowrap!important;overflow-x:auto;
    -webkit-overflow-scrolling:touch;scroll-snap-type:x proximity;
    scrollbar-width:none;-ms-overflow-style:none;margin:0;padding:0 0 4px;
    justify-content:flex-start!important}
  .draw-tile-row::-webkit-scrollbar{display:none}
  .draw-tile-row .draw-mob-col{flex:0 0 68px!important;min-width:0;scroll-snap-align:start}
  .draw-tile-row .draw-ref{width:auto!important;margin-bottom:0!important}
  .draw-tile-row .draw-size-pill,.draw-tile-row .draw-count-pill,
  .draw-tile-row .draw-enhance-btn,.draw-tile-row .draw-advanced-toggle,
  .draw-tile-row .draw-ref-btn{
    flex-direction:column!important;justify-content:center!important;align-items:center!important;
    gap:5px!important;width:68px!important;height:auto!important;padding:10px 6px!important;
    box-sizing:border-box!important;text-align:center;font-size:.72rem!important;
    font-weight:600!important;white-space:normal!important;border-radius:10px!important}
  .draw-tile-row .draw-size-pill>span,.draw-tile-row .draw-count-pill>span{
    flex:none;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .draw-tile-row .draw-size-pill>svg:nth-of-type(2),
  .draw-tile-row .draw-count-pill>svg:nth-of-type(2){display:none}
  .draw-tile-row .draw-size-pill>svg:first-of-type,.draw-tile-row .draw-count-pill>svg:first-of-type,
  .draw-tile-row .draw-enhance-btn>svg,.draw-tile-row .draw-advanced-toggle>svg,
  .draw-tile-row .draw-ref-btn>svg{width:18px;height:18px}
  .draw-tile-row .draw-neg-wrap,.draw-tile-row .draw-extra-wrap{width:auto;margin-bottom:0}
  .draw-tile-row .draw-enhance-btn{margin-bottom:0}
  #video-audio-toggle.draw-advanced-toggle{margin-bottom:0!important}
  /* Reference is always a plain 68px tile, same as every other option — the
     thumbnail preview(s), once attached, live in .draw-ref-preview-row
     (a sibling that comes after the whole tile strip in the markup) instead
     of inside the Reference tile or expanding it, so they land on their own
     full-width row below the tile strip rather than off to the right of it. */
  .draw-ref-preview-row{display:flex;flex-wrap:wrap;gap:6px;width:100%;margin-top:6px}
  /* "More" expander is desktop-only — on mobile everything lives in the sheet. */
  .draw-more-btn{display:none!important}
  .draw-more-extra,.draw-more-extra.open{display:contents!important}
  /* Full-width control rows (match .mts-model-select / .mts-action-btn look) */
  .draw-model-pill,.draw-size-pill,.draw-count-pill,.draw-ref-btn,.draw-enhance-btn,.draw-advanced-toggle,.draw-extra-toggle{
    width:100%;box-sizing:border-box;justify-content:flex-start;gap:9px;
    padding:11px 13px;font-size:.88rem;font-weight:500;border-radius:10px;
    border:1.5px solid var(--border);background:var(--bg);color:var(--text)}
  .draw-model-pill{max-width:100%}
  /* The shared full-width-row rule above sets color:var(--text) for every
     control (Size/Qty/Ref/etc. are neutral inputs) — but the Model pill's
     label should stay the same primary-blue shade as text mode's model pill
     (.composer-model-label), not read as a plain neutral input. */
  .draw-model-pill{color:var(--primary)}
  .draw-model-pill>span,.draw-size-pill>span,.draw-count-pill>span{max-width:none;text-align:left!important}
  /* Push the dropdown chevron (2nd inline svg) to the right edge */
  .draw-model-pill>svg:nth-of-type(2),.draw-size-pill>svg:nth-of-type(2),.draw-count-pill>svg:nth-of-type(2){margin-left:auto}
  .draw-ref,.draw-neg-wrap,.draw-extra-wrap{width:100%;margin-bottom:8px}
  .draw-extra-toggle{width:100%;box-sizing:border-box;justify-content:flex-start;gap:9px;padding:11px 13px;font-size:.88rem;font-weight:500;border-radius:10px;border:1.5px solid var(--border);background:var(--bg);color:var(--text)}
  .draw-extra-toggle.has-value{border-color:var(--primary);color:var(--primary);background:color-mix(in srgb,var(--primary) 8%,transparent)}
  .draw-enhance-btn{margin-bottom:8px}
  /* Video's Audio toggle is a bare button (unlike draw's Enhance/Negative
     prompt/Extra, which are wrapped and get the .draw-ref/.draw-neg-wrap/
     .draw-extra-wrap margin above) — give it the same 8px stacking gap so
     the video Options section doesn't look cramped next to draw's. */
  #video-audio-toggle{margin-bottom:8px}
  .draw-size-strip{display:block;width:100%}
  .draw-advanced-toggle.has-value{border-color:var(--primary);color:var(--primary);background:color-mix(in srgb,var(--primary) 8%,transparent)}
  /* Full label text on the mobile sheet — icon-only is a desktop-only space saving.
     (The 40x40 square sizing above is now itself wrapped in min-width:769px, so
     there's nothing to undo here anymore — this rule just needs to win back the
     label visibility from the unscoped .draw-btn-label{display:none} default.) */
  .draw-btn-label{display:inline}
  /* Footer — sticky action bar */
  .draw-sheet-footer{display:flex;gap:10px;padding:12px 14px;border-top:1px solid var(--border);position:sticky;bottom:0;background:var(--surface)}
  .draw-sheet-exit,.draw-sheet-done{flex:1;padding:12px 14px;border-radius:10px;font-size:.86rem;font-weight:650;cursor:pointer;font-family:inherit;-webkit-tap-highlight-color:transparent}
  .draw-sheet-exit{background:var(--bg);border:1.5px solid var(--border);color:var(--muted)}
  .draw-sheet-exit:active{background:var(--border)}
  .draw-sheet-done{background:var(--primary);border:1.5px solid var(--primary);color:#fff}
  .draw-sheet-done:active{filter:brightness(.95)}

  /* The "Draw options" collapsed strip is intentionally disabled — the "+"
     button (#compact-more-btn, always visible in composer-tools-right) now
     opens the mode's own sheet directly (see openToolSheet() in
     dashboard-ui.js), so a second dedicated affordance is redundant. The
     .draw-active-strip element itself stays in the DOM (harmless, display:
     none from the base rule) in case it's wanted again later. */
  .composer-card.draw-mode #composer-quick-strip{display:none!important}

  /* Video mode — same bottom-sheet mechanics as draw mode, scoped by ID. */
  .composer-card.video-mode #video-mode-bar{
    position:fixed;left:0;right:0;bottom:0;z-index:900;
    flex-direction:column;align-items:stretch;gap:0;
    background:var(--surface);border-top:1px solid var(--border);
    border-radius:20px 20px 0 0;box-shadow:0 -8px 40px rgba(0,0,0,.18);
    max-height:80vh;overflow-y:auto;-webkit-overflow-scrolling:touch;
    padding:0;padding-bottom:calc(env(safe-area-inset-bottom,0px) + 8px);
    transform:translateY(100%);
    transition:transform .3s cubic-bezier(.16,1,.3,1);
  }
  .composer-card.video-mode #video-mode-bar.draw-sheet-open{transform:translateY(0)}
  .composer-card.video-mode #composer-quick-strip{display:none!important}

  /* Audio mode — same bottom-sheet mechanics as draw/video mode, scoped by ID. */
  .composer-card.audio-mode #audio-mode-bar{
    position:fixed;left:0;right:0;bottom:0;z-index:900;
    flex-direction:column;align-items:stretch;gap:0;
    background:var(--surface);border-top:1px solid var(--border);
    border-radius:20px 20px 0 0;box-shadow:0 -8px 40px rgba(0,0,0,.18);
    max-height:80vh;overflow-y:auto;-webkit-overflow-scrolling:touch;
    padding:0;padding-bottom:calc(env(safe-area-inset-bottom,0px) + 8px);
    transform:translateY(100%);
    transition:transform .3s cubic-bezier(.16,1,.3,1);
  }
  .composer-card.audio-mode #audio-mode-bar.draw-sheet-open{transform:translateY(0)}
  .composer-card.audio-mode #composer-quick-strip{display:none!important}
}

.msg-content,.msg-bubble,.markdown-body,pre{word-break:break-word;overflow-wrap:anywhere;max-width:100%;}
/* `content-visibility: auto` + contain-intrinsic-size used to sit here as a
   "lightweight virtualization" perf trick: skip layout/paint for messages
   scrolled off-screen, using a 180px placeholder height until each message
   is actually measured. In practice this made the scrollbar thumb visibly
   grow/shrink while just scrolling an existing, unchanged chat — every
   message far enough off-screen (above OR below the viewport) reverts to
   the 180px placeholder, so scrollHeight (and the thumb size) kept
   fluctuating as different messages entered/left the "close enough to
   render" window, even with nothing new added to the chat. Reported: "the
   scroll bar was this big, then became small... same chat, nothing was
   added... becomes big again as I scroll down." Chat pages are capped at
   MSG_PAGE_SIZE (40) messages, so the perf gain wasn't worth a visibly
   broken scrollbar — removed. */
@keyframes msgPopIn { from { opacity: 0; transform: translateY(10px) scale(.98); } to { opacity: 1; transform: none; } }
.msg.msg-enter { animation: msgPopIn .28s cubic-bezier(.16,1,.3,1) both; }
body.reduced-motion .msg.msg-enter { animation: none; }

/* Gentle press feedback for icon/utility buttons */
.copy-btn, .quote-btn, .msg-edit-btn, .msg-branch-btn,
.code-copy-btn, .code-save-btn, .code-wrap-btn, .session-item-pin, .session-item-actions button,
.ccs-badge {
  transition: transform .1s ease, background .15s ease, color .15s ease;
}
.copy-btn:active, .quote-btn:active, .msg-edit-btn:active, .msg-branch-btn:active,
.code-copy-btn:active, .code-save-btn:active, .code-wrap-btn:active, .session-item-pin:active, .session-item-actions button:active {
  transform: scale(.92);
}
body.reduced-motion .copy-btn:active, body.reduced-motion .quote-btn:active,
body.reduced-motion .msg-edit-btn:active, body.reduced-motion .msg-branch-btn:active,
body.reduced-motion .code-copy-btn:active, body.reduced-motion .code-save-btn:active, body.reduced-motion .code-wrap-btn:active,
body.reduced-motion .session-item-pin:active, body.reduced-motion .session-item-actions button:active {
  transform: none;
}
/* G8 — "Different model" rerun button: pill/badge shape (like .model-badge)
   instead of the plain flat Copy/Retry look, so it visibly reads as a
   distinct, clickable option rather than a same-family text action. */
.model-rerun-btn {
  border: 1px solid var(--muted);
  border-radius: 999px;
  background: none;
  color: var(--muted);
  padding: 3px 10px 3px 8px;
}
.model-rerun-btn:hover {
  background: var(--bg);
  color: var(--text);
  border-color: var(--muted);
}

pre{overflow-x:auto;}
/* -- Sidebar footer -- */
.sf-footer{flex-shrink:0;}
/* Padding is fixed (app.css's 11px 12px 14px) regardless of chat state —
   previously tightened to 8px 12px 9px once a chat had messages (tracking
   the context-meter's visibility), which shifted the whole footer's height
   every time a chat went from empty to active. The context meter is now
   always visible for logged-in users (see updateCtxMeter() in
   dashboard-ui.js), so there's no longer a state where that made sense. */
.sf-avatar{width:36px;height:36px;border-radius:9px;background:var(--primary);color:#fff;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:.95rem;flex-shrink:0;}
/* -- Management modal -- */
@keyframes mgmtIn{from{opacity:0;transform:scale(.95) translateY(16px);}to{opacity:1;transform:none;}}
.mgmt-card{display:flex;align-items:flex-start;gap:14px;padding:18px;background:var(--surface);border:1px solid var(--border);border-radius:14px;text-decoration:none;color:inherit;cursor:pointer;transition:all .2s;font-family:inherit;}
.mgmt-card:hover{transform:translateY(-3px);box-shadow:0 10px 28px rgba(0,0,0,.12);border-color:var(--primary);}
.mgmt-card strong{display:block;font-size:1rem;font-weight:600;color:var(--text);margin-bottom:3px;}
.mgmt-card p{margin:0;font-size:.82rem;color:var(--muted);line-height:1.4;}
.mgmt-icon{width:46px;height:46px;border-radius:11px;display:flex;align-items:center;justify-content:center;flex-shrink:0;}
/* -- Mobile -- */
@media(max-width:768px){
  .app-main{max-width:100vw;}
  .app-sidebar{position:fixed;left:0;top:0;z-index:100;transform:translateX(-100%);transition:transform .3s cubic-bezier(.16,1,.3,1);}
  .app-sidebar.open{transform:translateX(0);box-shadow:4px 0 24px rgba(0,0,0,.3);}
}

/* -- User Profile Button -- */
.sf-user-btn {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 10px 12px; background: none; border: none; cursor: pointer;
  border-radius: 10px; text-align: left; transition: background .2s;
}
.sf-user-btn:hover { background: var(--surface-2, rgba(0,0,0,.05)); }

/* -- Dropdown -- */
.sf-dropdown {
  position: absolute; bottom: calc(100% + 8px); left: 8px;
  width: calc(100% - 16px);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 14px; padding: 6px;
  box-shadow: 0 -8px 40px rgba(0,0,0,.18);
  z-index: 200;
  opacity: 0; visibility: hidden; transform: translateY(8px);
  transition: all .22s cubic-bezier(.16,1,.3,1);
}
.sf-dropdown.show { opacity: 1; visibility: visible; transform: translateY(0); }

.sf-dropdown-header {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 10px 14px 10px;
}
.sf-dropdown-divider { height: 1px; background: var(--border); margin: 4px 0; }

.sf-dropdown-item {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 12px; color: var(--text); text-decoration: none;
  border-radius: 8px; font-size: 0.75rem; font-weight: 500;
  background: none; border: none; width: 100%; text-align: left; cursor: pointer;
  transition: background .15s, color .15s; font-family: inherit;
}
.sf-dropdown-item:hover { background: var(--surface-2, rgba(0,0,0,.05)); }
.sf-dropdown-item svg { flex-shrink: 0; color: var(--muted); }
.sf-dropdown-danger { color: #ef4444 !important; }
.sf-dropdown-danger:hover { background: rgba(239,68,68,.1) !important; }
.sf-dropdown-danger svg { color: #ef4444 !important; }

/* -- Composer Card ------------------------------------------- */
.chat-input-wrap {
  padding: 10px 16px 8px;
  background: var(--surface);
  border-top: 1px solid var(--border);
  flex-shrink: 0;
}

.composer-card {
  display: flex;
  flex-direction: column;
  background: var(--bg);
  border: 1.5px solid var(--border);
  border-radius: 14px;
  padding: 10px 12px 8px;
  transition: border-color .18s, box-shadow .18s;
  gap: 6px;
}
.composer-card:focus-within {
  border-color: color-mix(in srgb, var(--primary) 55%, var(--border-strong));
  box-shadow: 0 0 10px 0 var(--accent-ring);
}

#chat-input {
  flex: 1;
  border: none;
  background: transparent;
  resize: none;
  font-size: .92rem;
  font-family: inherit;
  color: var(--text);
  outline: none;
  max-height: 50vh;
  min-height: 24px;
  overflow-y: hidden;
  line-height: 1.55;
  padding: 0;
  display: block;
  width: 100%;
  caret-color: var(--primary);
}
#chat-input::placeholder { color: var(--muted); }

/* -- Toolbar -- */
.composer-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 4px;
  padding: 6px 10px 8px;
  border-top: 1px solid var(--border);
  flex-wrap: nowrap;
  min-height: 44px;
}

.composer-tools-left {
  display: flex;
  align-items: center;
  gap: 1px;
  flex: 1;
  min-width: 0;
  overflow: hidden;
  flex-wrap: nowrap;
}

.composer-tools-right {
  display: flex;
  align-items: center;
  flex-shrink: 0;
  margin-left: 6px;
}

/* Guests get the free-trial count in the floating #composer-swipe-hint
   bubble above the composer (see dashboard.php/dashboard.js) at every
   screen size now — this small toolbar copy would just duplicate it. */
#guest-trial-counter { display: none !important; }

/* Tool buttons */
.composer-tool-btn {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 8px;
  background: none;
  border: none;
  cursor: pointer;
  border-radius: 7px;
  color: var(--muted);
  font-size: .78rem;
  font-family: inherit;
  font-weight: 500;
  transition: background .15s, color .15s;
  white-space: nowrap;
}
.composer-tool-btn:hover {
  background: var(--surface-2, rgba(0,0,0,.06));
  color: var(--text);
}
.composer-tool-btn svg { flex-shrink: 0; }

/* Export dropdown */
.export-wrap { display: inline-flex; position: relative; }
.export-menu {
  position: absolute;
  bottom: calc(100% + 8px);
  right: 0;
  background: var(--surface, #fff);
  border: 1px solid var(--border, rgba(0,0,0,.1));
  border-radius: 10px;
  padding: 5px;
  box-shadow: 0 8px 24px rgba(0,0,0,.14);
  min-width: 170px;
  z-index: 200;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.export-menu-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  border: none;
  background: none;
  border-radius: 7px;
  color: var(--text, #0f172a);
  font-size: .82rem;
  font-family: inherit;
  cursor: pointer;
  text-align: left;
  white-space: nowrap;
}
.export-menu-item:hover { background: var(--surface-2, rgba(0,0,0,.05)); }
.export-menu-item small { color: var(--muted, #64748b); margin-left: auto; }
.export-menu-item svg { color: var(--muted, #64748b); flex-shrink: 0; }

/* Temperature pill */
.composer-temp-pill {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 8px;
  border-radius: 7px;
  color: var(--muted);
  font-size: .78rem;
  cursor: default;
}
.composer-temp-pill input[type=range] {
  -webkit-appearance: none;
  height: 3px;
  border-radius: 2px;
  background: var(--border);
  outline: none;
  cursor: pointer;
}
.composer-temp-pill input[type=range]::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 12px; height: 12px;
  border-radius: 50%;
  background: var(--primary);
  cursor: pointer;
}
.temp-display {
  font-size: .75rem;
  color: var(--muted);
  min-width: 22px;
  font-variant-numeric: tabular-nums;
}

/* char counter */
.char-counter {
  font-size: .72rem;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  min-width: 20px;
  text-align: right;
}

/* Send button */
.send-btn {
  background: var(--primary);
  color: #fff;
  border: none;
  border-radius: 8px;
  width: 32px; height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  flex-shrink: 0;
  transition: background .15s, transform .1s;
}
.send-btn:hover   { background: var(--primary-hover, #1d4ed8); }
.send-btn:active  { transform: scale(.92); }
.send-btn:disabled { opacity: .38; cursor: not-allowed; }

/* hint */

/* Remove old header space */
.chat-header { display: none !important; }
.sys-prompt-bar { display: none; }

/* -- Composer wrap -- */
.chat-input-wrap {
  padding: 8px 14px 8px;
  background: var(--surface);
  border-top: 1px solid var(--border);
  flex-shrink: 0;
}

/* Persona active strip */
.composer-persona-strip {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  margin-bottom: 6px;
  background: color-mix(in srgb, var(--primary) 8%, transparent);
  border: 1px solid color-mix(in srgb, var(--primary) 20%, transparent);
  border-radius: 8px;
}

/* -- Card -- */
.composer-card {
  display: flex;
  flex-direction: column;
  background: var(--bg);
  border: 1.5px solid var(--border);
  border-radius: 14px;
  padding: 0;
  overflow: hidden;
  transition: border-color .18s, box-shadow .18s;
}

.composer-model-row { display: none !important; }
.composer-chat-title { display: none !important; }

.composer-model-pill {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 8px 3px 6px;
  border-radius: 7px;
  cursor: pointer;
  transition: background .15s;
  flex-shrink: 0;
}
.composer-model-pill:hover { background: var(--border); }
.composer-model-pill svg { color: var(--muted); flex-shrink: 0; }

.composer-model-select {
  background: transparent;
  border: none;
  outline: none;
  font-size: .78rem;
  color: var(--text);
  font-family: inherit;
  font-weight: 600;
  cursor: pointer;
  padding: 0;
  max-width: 140px;
}
.composer-model-select option,
.composer-model-select optgroup { background: var(--surface); color: var(--text); }

.composer-divider {
  width: 1px; height: 16px;
  background: var(--border);
  margin: 0 3px;
  flex-shrink: 0;
}

.composer-tool-btn:hover { background: var(--border); color: var(--text); }
.composer-tool-btn.active { color: var(--primary); }


.welcome-screen {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 48px 24px 32px;
  gap: 10px;
  max-width: 680px;
  margin: 0 auto;
}
.welcome-logo { margin-bottom: 6px; }
.welcome-screen h2 { font-size: 1.5rem; font-weight: 700; color: var(--text); margin: 0; }
.welcome-sub { font-size: .9rem; color: var(--muted); margin: 0; min-height: 22px; }

.welcome-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  justify-content: center;
  margin-top: 8px;
  min-height: 36px;
}
.chip {
  padding: 8px 14px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 99px;
  font-size: .84rem;
  cursor: pointer;
  color: var(--text);
  transition: all .18s;
  white-space: nowrap;
  animation: chipIn .3s cubic-bezier(.16,1,.3,1) both;
}
.chip:hover {
  background: var(--primary);
  color: #fff;
  border-color: var(--primary);
  transform: translateY(-2px);
  box-shadow: 0 4px 12px color-mix(in srgb, var(--primary) 30%, transparent);
}
@keyframes chipIn {
  from { opacity: 0; transform: translateY(8px) scale(.96); }
  to   { opacity: 1; transform: none; }
}
.chip:nth-child(1) { animation-delay: .04s }
.chip:nth-child(2) { animation-delay: .08s }
.chip:nth-child(3) { animation-delay: .12s }
.chip:nth-child(4) { animation-delay: .16s }
.chip:nth-child(5) { animation-delay: .20s }
.chip:nth-child(6) { animation-delay: .24s }
.chip:nth-child(7) { animation-delay: .28s }
.chip:nth-child(8) { animation-delay: .32s }

.welcome-refresh-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 4px;
  padding: 6px 14px;
  background: none;
  border: 1px solid var(--border);
  border-radius: 99px;
  font-size: .78rem;
  color: var(--muted);
  cursor: pointer;
  font-family: inherit;
  transition: all .18s;
}
.welcome-refresh-btn:hover { border-color: var(--primary); color: var(--primary); }
.welcome-refresh-btn.spinning svg { animation: spin .6s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

/* ── Guest Welcome Screen ────────────────────────────────────────────────────── */
#guest-welcome {
  display: flex; flex-direction: column; width: 100%;
  animation: gwFadeIn .4s ease;
  /* Fill the full chat-messages container — no margin or gap */
  margin: 0; flex: 1 0 auto;
}
@keyframes gwFadeIn { from { opacity:0; transform:translateY(12px); } to { opacity:1; transform:none; } }

/* Hero — themed gradient backdrop with floating decorative orbs */
.gw-hero {
  position: relative; overflow: hidden;
  border-bottom: 1px solid var(--border);
  padding: 64px 32px 52px; text-align: center;
  background:
    radial-gradient(120% 80% at 50% -10%, color-mix(in srgb, var(--primary) 16%, var(--bg)) 0%, var(--bg) 62%);
}
.gw-hero::before, .gw-hero::after {
  content: ''; position: absolute; border-radius: 50%; z-index: 0;
  filter: blur(60px); opacity: .5; pointer-events: none;
}
.gw-hero::before {
  width: 320px; height: 320px; top: -120px; left: -80px;
  background: color-mix(in srgb, var(--primary) 38%, transparent);
}
.gw-hero::after {
  width: 260px; height: 260px; top: -60px; right: -70px;
  background: color-mix(in srgb, var(--primary) 22%, transparent);
}
.gw-hero > * { position: relative; z-index: 1; }
.gw-hero-logo {
  width: 76px; height: 76px; margin: 0 auto 20px; border-radius: 22px;
  display: flex; align-items: center; justify-content: center;
  background: var(--surface);
  border: 1px solid color-mix(in srgb, var(--primary) 25%, var(--border));
  box-shadow: 0 12px 40px color-mix(in srgb, var(--primary) 22%, transparent);
}
.gw-hero h1 {
  font-size: 2.2rem; font-weight: 800; color: var(--text);
  margin: 0 0 8px; line-height: 1.12; letter-spacing: -.02em;
}
.gw-hero-tagline {
  font-size: 1.15rem; font-weight: 700; margin: 0 0 16px; letter-spacing: -.01em;
  background: linear-gradient(90deg, var(--primary), color-mix(in srgb, var(--primary) 55%, var(--text)));
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: var(--primary);
}
.gw-hero-desc {
  font-size: .94rem; color: var(--muted); margin: 0 auto 24px;
  line-height: 1.7; text-align: center; max-width: 600px;
}
.gw-hero-desc strong { color: var(--text); font-weight: 700; }
.gw-hero-trial {
  display: inline-flex; align-items: center; gap: 8px;
  background: color-mix(in srgb, var(--primary) 12%, transparent);
  border: 1.5px solid color-mix(in srgb, var(--primary) 30%, transparent);
  color: var(--primary); border-radius: 99px; padding: 7px 18px;
  font-size: .82rem; font-weight: 700; margin-bottom: 24px;
}
.gw-hero-trial .pulse {
  width: 8px; height: 8px; border-radius: 50%; background: var(--primary);
  box-shadow: 0 0 0 0 color-mix(in srgb, var(--primary) 60%, transparent);
  animation: gwPulse 2s infinite;
}
@keyframes gwPulse {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--primary) 55%, transparent); }
  70%  { box-shadow: 0 0 0 9px transparent; }
  100% { box-shadow: 0 0 0 0 transparent; }
}
/* Provider pills strip under hero CTAs */
.gw-providers {
  display: flex; flex-wrap: wrap; gap: 8px; justify-content: center;
  margin-top: 30px;
}
.gw-providers-label {
  width: 100%; text-align: center; font-size: .68rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .12em; color: var(--muted);
  margin-bottom: 4px;
}
.gw-prov-pill {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 99px; padding: 6px 14px; font-size: .78rem;
  font-weight: 600; color: var(--text);
}
.gw-prov-pill .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--primary); }
.gw-hero-btns { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; }
.gw-hero-btns a { text-decoration: none; }
.gw-btn-primary {
  display: inline-flex; align-items: center; gap: 7px;
  background: var(--primary); color: #fff; border-radius: 10px;
  padding: 11px 24px; font-size: .9rem; font-weight: 700;
  border: none; cursor: pointer; font-family: inherit;
  transition: opacity .15s;
}
.gw-btn-primary:hover { opacity: .88; }
.gw-btn-secondary {
  display: inline-flex; align-items: center; gap: 7px;
  background: var(--surface); color: var(--text); border-radius: 10px;
  padding: 10px 22px; font-size: .9rem; font-weight: 600;
  border: 1.5px solid var(--border); cursor: pointer; font-family: inherit;
  transition: border-color .15s, color .15s;
}
.gw-btn-secondary:hover { border-color: var(--primary); color: var(--primary); }

/* Feature highlights bar */
/* ── How it works steps ── */
.gw-how {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: 14px; padding: 24px 24px 28px;
  max-width: 920px; margin: 0 auto;
  border-bottom: 1px solid var(--border);
}
.gw-step {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 18px;
  padding: 22px 18px 20px;
  display: flex; flex-direction: column; align-items: center;
  text-align: center; gap: 10px;
  position: relative;
}
.gw-step-num {
  width: 44px; height: 44px; border-radius: 50%;
  background: var(--primary);
  color: #fff;
  display: flex; align-items: center; justify-content: center;
  font-size: 1.05rem; font-weight: 800; flex-shrink: 0;
  box-shadow: 0 3px 10px color-mix(in srgb, var(--primary) 35%, transparent);
}
.gw-step-title { font-size: .84rem; font-weight: 700; color: var(--text); line-height: 1.3; }
.gw-step-body  { font-size: .75rem; color: var(--muted); line-height: 1.55; }

/* Sections */
.gw-body { padding: 40px 24px; width: 100%; box-sizing: border-box; }
.gw-body .gw-section-hd, .gw-body .gw-features, .gw-body .gw-fair-card,
.gw-body .gw-legal, .gw-body .gw-zdr-callout, .gw-body .gw-slider-wrap,
.gw-body .gw-plans, .gw-body .gw-packages, .gw-body .gw-intro-blurb {
  max-width: 920px; margin-left: auto; margin-right: auto;
}
.gw-section { margin-bottom: 32px; }
.gw-section-hd {
  display: flex; align-items: center; gap: 12px;
  margin-bottom: 20px; padding-bottom: 14px;
  position: relative;
  border-bottom: 1px solid var(--border);
}
.gw-section-hd::after {
  content: ''; position: absolute; left: 0; bottom: -1px;
  width: 64px; height: 2px; border-radius: 2px;
  background: linear-gradient(90deg, var(--primary), color-mix(in srgb, var(--primary) 30%, transparent));
}
.gw-section-icon {
  width: 38px; height: 38px; border-radius: 11px; flex-shrink: 0;
  background: linear-gradient(135deg, color-mix(in srgb, var(--primary) 22%, transparent), color-mix(in srgb, var(--primary) 8%, transparent));
  border: 1px solid color-mix(in srgb, var(--primary) 22%, transparent);
  display: flex; align-items: center; justify-content: center;
  color: var(--primary);
  box-shadow: 0 4px 12px color-mix(in srgb, var(--primary) 14%, transparent);
}
.gw-section-title { font-size: 1.08rem; font-weight: 800; color: var(--text); letter-spacing: -.01em; }
.gw-section-sub { font-size: .8rem; color: var(--muted); margin-left: auto; font-weight: 500; }

/* Intro blurb */
.gw-intro-blurb {
  display: flex; align-items: flex-start; gap: 12px;
  background: color-mix(in srgb, var(--primary) 6%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--primary) 20%, transparent);
  border-radius: 12px; padding: 14px 16px; margin-bottom: 28px;
  font-size: .84rem; color: var(--text); line-height: 1.6;
}
.gw-intro-blurb strong { font-weight: 700; color: var(--text); }

/* Plan cards */
/* Grid mode (≤ threshold) */
.gw-plans { display: grid; grid-template-columns: repeat(auto-fill, minmax(175px, 1fr)); gap: 12px; }
/* Slider mode (> threshold) */
.gw-slider-wrap { position: relative; }
.gw-slider-track {
  display: flex; gap: 12px;
  overflow-x: auto; scroll-snap-type: x mandatory; scroll-behavior: smooth;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none; padding: 4px 2px 8px;
}
.gw-slider-track::-webkit-scrollbar { display: none; }
.gw-slider-track .gw-plan-card { flex: 0 0 190px; scroll-snap-align: start; }
.gw-slider-track .gw-pkg-card  { flex: 0 0 155px; scroll-snap-align: start; }
.gw-slider-btn {
  position: absolute; top: 50%; transform: translateY(-50%);
  width: 30px; height: 30px; border-radius: 50%;
  background: var(--surface); border: 1.5px solid var(--border);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer; z-index: 2; color: var(--text);
  box-shadow: 0 2px 8px rgba(0,0,0,.12); transition: background .15s, opacity .15s;
}
.gw-slider-btn:hover { background: var(--border); }
.gw-slider-btn[disabled] { opacity: .25; cursor: default; pointer-events: none; }
.gw-slider-btn.prev { left: -15px; }
.gw-slider-btn.next { right: -15px; }

.gw-plan-card {
  background: var(--surface); border: 1.5px solid var(--border); border-radius: 14px;
  padding: 18px 16px; display: flex; flex-direction: column; gap: 8px;
  transition: border-color .2s, box-shadow .2s; position: relative;
}
.gw-plan-card:hover { border-color: var(--primary); box-shadow: 0 4px 20px color-mix(in srgb,var(--primary) 12%,transparent); }
.gw-plan-card.featured {
  border-color: var(--primary);
  box-shadow: 0 0 0 2px color-mix(in srgb,var(--primary) 18%,transparent), 0 6px 24px color-mix(in srgb,var(--primary) 15%,transparent);
}
.gw-plan-badge {
  position: absolute; top: -10px; left: 50%; transform: translateX(-50%);
  background: var(--primary); color: #fff; font-size: .62rem; font-weight: 800;
  padding: 3px 12px; border-radius: 20px; white-space: nowrap; letter-spacing: .06em; text-transform: uppercase;
}
.gw-plan-name { font-size: .82rem; font-weight: 700; color: var(--muted); }
.gw-plan-price { font-size: 1.4rem; font-weight: 800; color: var(--text); line-height: 1; }
.gw-plan-price small { font-size: .7rem; font-weight: 600; color: var(--muted); }
.gw-plan-credits { font-size: .75rem; color: var(--primary); font-weight: 700; }
.gw-plan-features { list-style: none; padding: 0; margin: 4px 0 0; display: flex; flex-direction: column; gap: 4px; }
.gw-plan-features li { font-size: .72rem; color: var(--muted); display: flex; align-items: flex-start; gap: 5px; }
.gw-plan-features li svg { flex-shrink: 0; color: var(--primary); margin-top: 1px; }
.gw-plan-cta {
  margin-top: auto; padding-top: 12px;
  text-align: center; font-size: .78rem; font-weight: 700;
  color: var(--primary); cursor: pointer;
}

/* Package cards */
.gw-packages { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 10px; }
.gw-slider-track.gw-pkgs-track { gap: 10px; }
.gw-pkg-card {
  background: var(--surface); border: 1.5px solid var(--border); border-radius: 12px;
  padding: 14px 12px; text-align: center; transition: border-color .2s;
}
.gw-pkg-card:hover { border-color: var(--primary); }
.gw-pkg-card.best { border-color: var(--primary); background: color-mix(in srgb,var(--primary) 5%,var(--surface)); }
.gw-pkg-price { font-size: 1.2rem; font-weight: 800; color: var(--text); }
.gw-pkg-credits { font-size: .75rem; font-weight: 700; color: var(--primary); margin: 2px 0; }
.gw-pkg-name { font-size: .68rem; color: var(--muted); }

/* Fair use table */
/* Fair-use — polished card table */
.gw-fair-card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 16px; overflow: hidden;
  box-shadow: 0 2px 14px rgba(0,0,0,.04);
}
.gw-fair-table { width: 100%; border-collapse: collapse; font-size: .85rem; }
.gw-fair-table thead th {
  font-size: .68rem; text-transform: uppercase; letter-spacing: .07em;
  font-weight: 800; color: var(--muted);
  padding: 13px 16px; text-align: left;
  background: color-mix(in srgb, var(--primary) 5%, var(--surface));
  border-bottom: 1px solid var(--border);
}
.gw-fair-table thead th:not(:first-child) { text-align: center; }
.gw-fair-table tbody td { padding: 14px 16px; border-bottom: 1px solid var(--border); color: var(--text); text-align: center; }
.gw-fair-table tbody tr:last-child td { border-bottom: none; }
.gw-fair-table tbody tr:hover td { background: color-mix(in srgb, var(--primary) 3%, transparent); }
.gw-fair-plan {
  text-align: left !important; font-weight: 700; font-size: .9rem;
  display: flex; align-items: center; gap: 9px;
}
.gw-fair-plan .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--primary); flex-shrink: 0; }
/* Value pills */
.gw-fair-pill {
  display: inline-block; min-width: 54px; padding: 4px 12px;
  border-radius: 8px; font-weight: 700; font-size: .82rem;
  background: color-mix(in srgb, var(--primary) 11%, transparent); color: var(--primary);
}
.gw-fair-pill.unlimited {
  background: color-mix(in srgb, #10b981 12%, transparent); color: #10b981;
}
.gw-fair-pill.none { background: var(--border); color: var(--muted); font-weight: 600; }
.gw-fair-note {
  font-size: .74rem; color: var(--muted); padding: 11px 16px;
  background: color-mix(in srgb, var(--primary) 3%, transparent);
  border-top: 1px solid var(--border);
}

/* Divider with text */
.gw-divider {
  display: flex; align-items: center; gap: 12px; margin: 8px 0 24px;
  font-size: .72rem; color: var(--muted); text-transform: uppercase; letter-spacing: .07em;
}
.gw-divider::before,.gw-divider::after { content:''; flex:1; height:1px; background:var(--border); }

/* Footer CTA — card like gw-zdr-callout */
.gw-footer-cta {
  display: flex; gap: 16px; align-items: flex-start;
  background: color-mix(in srgb, var(--primary) 7%, var(--surface));
  border: 1.5px solid color-mix(in srgb, var(--primary) 28%, transparent);
  border-radius: 18px; padding: 24px 26px;
  box-shadow: 0 4px 20px color-mix(in srgb, var(--primary) 10%, transparent);
}
.gw-footer-cta-icon {
  width: 48px; height: 48px; border-radius: 14px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--primary) 15%, transparent); color: var(--primary);
}
.gw-footer-cta h3 { font-size: 1.2rem; font-weight: 800; margin: 0 0 5px; color: var(--text); letter-spacing: -.01em; }
.gw-footer-cta p { font-size: .88rem; color: var(--muted); margin: 0 0 16px; }
.gw-footer-cta .gw-hero-btns { justify-content: flex-start; }

/* Back link on AI responses */
.gw-back-link {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: .72rem; color: var(--primary); font-weight: 600; cursor: pointer;
  background: none; border: none; padding: 0; font-family: inherit;
  transition: opacity .15s;
}
.gw-back-link:hover { opacity: .75; }

/* ── Capability / feature cards ── */
.gw-features {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px;
}
.gw-feat-card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 16px; padding: 20px 18px;
  transition: border-color .2s, box-shadow .2s, transform .2s;
}
.gw-feat-card:hover {
  border-color: color-mix(in srgb, var(--primary) 45%, var(--border));
  box-shadow: 0 8px 26px color-mix(in srgb, var(--primary) 10%, transparent);
  transform: translateY(-2px);
}
.gw-feat-ic {
  width: 42px; height: 42px; border-radius: 12px; margin-bottom: 13px;
  display: flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--primary) 12%, transparent);
  color: var(--primary);
}
.gw-feat-card h4 { margin: 0 0 6px; font-size: .92rem; font-weight: 700; color: var(--text); }
.gw-feat-card p  { margin: 0; font-size: .78rem; color: var(--muted); line-height: 1.55; }

/* ── Available AI Models — flat, model-names-only chip cloud (see $_gmFlat) ──
   Rendered inside a .gw-slider-track (.gw-models-track): a fixed 2-row grid
   that flows chips into columns, so instead of the list growing tall with
   many wrap rows, it scrolls left/right exactly like the plan/package rows. */
.gw-models-track { align-items: flex-start; }
.gw-models-chips {
  display: grid; grid-auto-flow: column; grid-template-rows: repeat(2, auto);
  gap: 9px; width: max-content;
}
.gw-model-chip {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: .8rem; font-weight: 600; color: var(--text);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 99px; padding: 7px 14px; white-space: nowrap;
  transition: border-color .15s, box-shadow .15s, transform .15s, background .15s;
}
.gw-model-chip::before {
  content: ''; width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0;
  background: var(--primary);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary) 16%, transparent);
}
.gw-model-chip:hover {
  border-color: color-mix(in srgb, var(--primary) 45%, var(--border));
  background: color-mix(in srgb, var(--primary) 5%, var(--surface));
  box-shadow: 0 3px 12px color-mix(in srgb, var(--primary) 12%, transparent);
  transform: translateY(-1px);
}

/* ── Legal / info prose blocks (T&C, Privacy) ── */
.gw-legal { display: flex; flex-direction: column; gap: 10px; }
.gw-legal details {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 12px; overflow: hidden; transition: border-color .15s;
}
.gw-legal details[open] { border-color: color-mix(in srgb, var(--primary) 35%, var(--border)); }
.gw-legal summary {
  list-style: none; cursor: pointer; padding: 15px 18px;
  display: flex; align-items: center; gap: 11px;
  font-size: .9rem; font-weight: 700; color: var(--text);
  user-select: none;
}
.gw-legal summary::-webkit-details-marker { display: none; }
.gw-legal summary .chev {
  margin-left: auto; transition: transform .2s; color: var(--muted); flex-shrink: 0;
}
.gw-legal details[open] summary .chev { transform: rotate(180deg); }
.gw-legal summary .lic {
  width: 30px; height: 30px; border-radius: 8px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--primary) 12%, transparent); color: var(--primary);
}
.gw-legal-body { padding: 0 18px 18px 59px; font-size: .82rem; color: var(--muted); line-height: 1.7; }
.gw-legal-body p { margin: 0 0 10px; }
.gw-legal-body strong { color: var(--text); font-weight: 700; }
.gw-legal-body ul { margin: 6px 0 12px; padding-left: 18px; }
.gw-legal-body li { margin-bottom: 5px; }
.gw-legal-body a { color: var(--primary); font-weight: 600; text-decoration: none; }

/* ZDR highlight callout */
.gw-zdr-callout {
  display: flex; gap: 13px; align-items: flex-start;
  background: color-mix(in srgb, var(--primary) 7%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--primary) 25%, transparent);
  border-radius: 12px; padding: 15px 17px; margin: 4px 0 14px;
}
.gw-zdr-callout .shield {
  width: 36px; height: 36px; border-radius: 10px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--primary) 15%, transparent); color: var(--primary);
}
.gw-zdr-callout h5 { margin: 0 0 3px; font-size: .86rem; font-weight: 800; color: var(--text); }
.gw-zdr-callout p  { margin: 0; font-size: .78rem; color: var(--muted); line-height: 1.55; }

/* Footer secondary links */
.gw-footer-links {
  display: flex; gap: 18px; justify-content: center; flex-wrap: wrap;
  margin-top: 20px; font-size: .76rem;
}
.gw-footer-links a { color: var(--muted); text-decoration: none; font-weight: 600; transition: color .15s; }
.gw-footer-links a:hover { color: var(--primary); }

@media (max-width: 640px) {
  .gw-footer-cta-icon { display: none; }
  .gw-hero { padding: 40px 18px 32px; }
  .gw-hero h1 { font-size: 1.7rem; }
  .gw-hero-tagline { font-size: 1rem; }
  .gw-hero-desc { font-size: .85rem; }
  .gw-hero-logo { width: 64px; height: 64px; border-radius: 18px; }
  .gw-features { grid-template-columns: 1fr; }
  .gw-legal-body { padding-left: 18px; }
  .gw-how { grid-template-columns: 1fr; gap: 10px; padding: 16px; }
  .gw-step { flex-direction: row; text-align: left; align-items: flex-start; gap: 14px; padding: 16px; border-radius: 14px; }
  .gw-step-num { flex-shrink: 0; width: 38px; height: 38px; font-size: .9rem; }
  .gw-step-title, .gw-step-body { text-align: left; }
  .gw-feat:nth-child(2n) { border-right: none; }
  .gw-body { padding: 18px 14px; }
  .gw-plans { grid-template-columns: repeat(2, 1fr); }
  .gw-slider-btn { display: none; } /* arrows hidden on mobile; swipe instead */
  .gw-packages { grid-template-columns: repeat(3, 1fr); }
  .gw-intro-blurb { font-size: .8rem; }
  .gw-section-title { font-size: .98rem; }
  .gw-fair-card { overflow-x: auto; }
  .gw-fair-table { min-width: 440px; }
  .gw-fair-table thead th, .gw-fair-table tbody td { padding: 11px 12px; }
}

/* ==============================================
   COMPOSER CARD - REDESIGN
   ============================================== */

.chat-input-wrap {
  padding: 10px 20px 10px;
  background: transparent;
  border-top: none;
  flex-shrink: 0;
  flex-grow: 0;
  contain: layout;
}

/* Outer glow wrapper */
.composer-card {
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1.5px solid var(--border);
  border-radius: 18px;
  overflow: hidden;
  padding: 0;
  transition: border-color .22s, box-shadow .22s;
  box-shadow:
    0 2px 8px rgba(0,0,0,.06),
    0 1px 2px rgba(0,0,0,.04);
}

.composer-card:focus-within {
  border-color: color-mix(in srgb, var(--primary) 55%, var(--border-strong));
  box-shadow: 0 0 10px 0 var(--accent-ring);
}

/* -- Textarea -- */
#chat-input {
  flex: 0 0 auto;
  border: none;
  background: transparent;
  resize: none;
  font-size: .95rem;
  font-family: inherit;
  color: var(--text);
  outline: none;
  max-height: 50vh;
  min-height: 26px;
  overflow-y: hidden;
  line-height: 1.6;
  padding: 14px 16px 10px;
  width: 100%;
  display: block;
  box-sizing: border-box;
  caret-color: var(--primary);
}
#chat-input::placeholder {
  color: var(--muted);
  font-style: italic;
}

/* Themed scrollbar — desktop only, appears when content hits the max-height cap */
@media (min-width: 769px) {
  #chat-input::-webkit-scrollbar { width: 6px; }
  #chat-input::-webkit-scrollbar-track { background: transparent; border-radius: 99px; margin: 6px 0; }
  #chat-input::-webkit-scrollbar-thumb { background: color-mix(in srgb, var(--primary) 35%, transparent); border-radius: 99px; }
  #chat-input::-webkit-scrollbar-thumb:hover { background: color-mix(in srgb, var(--primary) 60%, transparent); }
  #chat-input { scrollbar-width: thin; scrollbar-color: color-mix(in srgb, var(--primary) 35%, transparent) transparent; }
}
@media (max-width: 768px) {
  #chat-input::-webkit-scrollbar { display: none; }
  #chat-input { scrollbar-width: none; }
}

/* -- Toolbar -- */
.composer-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 6px 8px 8px;
  border-top: 1px solid var(--border);
  background: color-mix(in srgb, var(--surface) 80%, var(--bg));
  gap: 4px;
}

.composer-tools-left {
  display: flex;
  align-items: center;
  gap: 1px;
  flex-wrap: nowrap;
  overflow: hidden;
}

.composer-tools-right {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-shrink: 0;
}

/* Model pill */
.composer-model-pill {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 5px 9px;
  border-radius: 8px;
  cursor: pointer;
  transition: background .15s;
  max-width: 180px;
}
.composer-model-pill svg { color: var(--primary); flex-shrink: 0; }

.composer-model-select {
  background: transparent;
  border: none;
  outline: none;
  font-size: .78rem;
  color: var(--text);
  font-family: inherit;
  font-weight: 700;
  cursor: pointer;
  padding: 0;
  max-width: 140px;
  text-overflow: ellipsis;
  overflow: hidden;
}
.composer-model-select optgroup {
  background: var(--surface);
  color: var(--text);
  font-weight: 500;
}

/* Divider */
.composer-divider {
  width: 1px;
  height: 16px;
  background: var(--border);
  margin: 0 4px;
  flex-shrink: 0;
}

/* Tool buttons */
.composer-tool-btn {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 5px 9px;
  background: none;
  border: none;
  cursor: pointer;
  border-radius: 8px;
  color: var(--muted);
  font-size: .78rem;
  font-family: inherit;
  font-weight: 500;
  transition: background .15s, color .15s;
  white-space: nowrap;
  flex-shrink: 0;
}
.composer-tool-btn:hover {
  background: color-mix(in srgb, var(--primary) 10%, transparent);
  color: var(--primary);
}
.composer-tool-btn:hover svg { color: var(--primary); }
.composer-tool-btn.active {
  color: var(--primary);
  background: color-mix(in srgb, var(--primary) 12%, transparent);
}

/* Temp pill */
.composer-temp-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 9px;
  color: var(--muted);
  font-size: .78rem;
  border-radius: 8px;
  transition: background .15s;
}
.composer-temp-pill:hover { background: color-mix(in srgb, var(--primary) 10%, transparent); }
.composer-temp-pill input[type=range] {
  -webkit-appearance: none;
  height: 3px;
  width: 56px;
  border-radius: 2px;
  background: var(--border);
  outline: none;
  cursor: pointer;
}
.composer-temp-pill input[type=range]::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 13px; height: 13px;
  border-radius: 50%;
  background: var(--primary);
  cursor: pointer;
  box-shadow: 0 1px 4px rgba(0,0,0,.2);
}
.temp-display {
  font-size: .73rem;
  color: var(--primary);
  min-width: 22px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* Char counter */
.char-counter {
  font-size: .72rem;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  min-width: 24px;
  text-align: right;
}

/* Send button - premium pill */
.send-btn {
  background: var(--primary);
  color: #fff;
  border: none;
  border-radius: 10px;
  width: 34px;
  height: 34px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  flex-shrink: 0;
  transition: background .15s, transform .12s, box-shadow .15s;
  box-shadow: 0 2px 8px color-mix(in srgb, var(--primary) 40%, transparent);
}
.send-btn:hover {
  background: var(--primary-hover, #1d4ed8);
  box-shadow: 0 4px 14px color-mix(in srgb, var(--primary) 50%, transparent);
  transform: translateY(-1px);
}
.send-btn:active  { transform: scale(.93) translateY(0); box-shadow: none; }
/* While streaming, the send button becomes the Stop control — give it a
   distinct color and gentle pulse so it reads clearly as "stop", not "send". */
#chat-input-row.streaming .send-btn {
  background: var(--danger, #ef4444);
  box-shadow: 0 2px 10px color-mix(in srgb, var(--danger, #ef4444) 45%, transparent);
  animation: stopBtnPulse 2s ease-in-out infinite;
}
#chat-input-row.streaming .send-btn:hover {
  background: var(--danger, #ef4444);
  filter: brightness(.92);
}
@keyframes stopBtnPulse {
  0%, 100% { box-shadow: 0 2px 10px color-mix(in srgb, var(--danger, #ef4444) 45%, transparent); }
  50%      { box-shadow: 0 2px 16px color-mix(in srgb, var(--danger, #ef4444) 70%, transparent); }
}
.send-btn:disabled {
  opacity: .35;
  cursor: not-allowed;
  box-shadow: none;
  transform: none;
}

/* Streaming state - card gets pulsing border */
.composer-card.streaming {
  border-color: var(--primary);
  box-shadow:
    0 0 0 3px color-mix(in srgb, var(--primary) 10%, transparent),
    0 4px 20px rgba(0,0,0,.08);
  animation: composerPulse 2s ease-in-out infinite;
}
@keyframes composerPulse {
  0%, 100% { box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary) 10%, transparent), 0 4px 20px rgba(0,0,0,.08); }
  50%       { box-shadow: 0 0 0 5px color-mix(in srgb, var(--primary) 18%, transparent), 0 6px 24px rgba(0,0,0,.1); }
}

/* Persona strip */
.composer-persona-strip {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 5px 12px;
  margin-bottom: 6px;
  background: color-mix(in srgb, var(--primary) 8%, transparent);
  border: 1px solid color-mix(in srgb, var(--primary) 22%, transparent);
  border-radius: 10px;
  font-size: .76rem;
}

/* ── Image attachment chips ──────────────────────────────────────── */
.img-chips-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  padding: 8px 12px 4px;
}
.img-chip {
  position: relative;
  display: inline-flex;
  border-radius: 8px;
  overflow: visible;
  flex-shrink: 0;
  animation: chipFadeIn .2s cubic-bezier(.16,1,.3,1);
}
@keyframes chipFadeIn {
  from { opacity:0; transform:scale(.8); }
  to   { opacity:1; transform:scale(1); }
}
.img-chip img {
  width: 54px;
  height: 54px;
  object-fit: cover;
  border-radius: 8px;
  border: 1.5px solid var(--border);
  display: block;
  transition: border-color .15s;
}
.img-chip:hover img { border-color: var(--primary); }
.img-chip-del {
  position: absolute;
  top: -5px; right: -5px;
  width: 18px; height: 18px;
  border-radius: 50%;
  background: var(--text);
  border: 2px solid var(--surface);
  color: var(--bg);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 9px;
  line-height: 1;
  padding: 0;
  transition: background .15s;
  z-index: 2;
}
.img-chip-del:hover { background: #ef4444; color: #fff; border-color: #ef4444; }

.file-chip {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 54px;
  max-width: 180px;
  padding: 0 26px 0 10px;
  border-radius: 8px;
  border: 1.5px solid var(--border);
  background: var(--surface);
  flex-shrink: 0;
  animation: chipFadeIn .2s cubic-bezier(.16,1,.3,1);
  transition: border-color .15s;
}
.file-chip:hover { border-color: var(--primary); }
.file-chip-icon { flex-shrink: 0; color: var(--primary); }
.file-chip-name {
  font-size: .74rem;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Composer chip mid-upload (api/attachment_upload.php in flight) — dimmed
   with a centered spinner over the image thumb, or the existing left-side
   spinner glyph for a document chip (reused inline in the chip markup). */
.img-chip.chip-uploading img,
.file-chip.chip-uploading { opacity: .55; }
.img-chip .chip-spinner {
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
}

/* ── Chat attachment cards (persisted uploads, rendered on the user's own
   message bubble — see _renderAttachmentCardsHTML in dashboard.js). These
   are read-only/no-download by design: an image card shows the derived
   thumbnail only (api/attachment_thumb.php), a document card is pure
   metadata with no link — see fair-use.php "Files you upload to chat". ── */
.msg-attachments {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 6px;
}
/* .msg-body is a column flex container with no align-items override, so its
   children stretch full-width by default — .msg-user .msg-bubble already
   opts out via align-self:flex-end (app.css) so the bubble hugs the right
   edge; without the same override here, .msg-attachments stayed full-width
   and its flex-start content rendered on the LEFT of the chat while the
   bubble sat on the right (reported bug). Attachments only ever render on
   user messages (see appendMessage()'s isUser guard), so no .msg-ai arm needed. */
.msg-user .msg-attachments {
  align-self: flex-end;
  justify-content: flex-end;
}
.attach-card { flex-shrink: 0; }
.attach-card-image {
  width: 96px;
  height: 96px;
  border-radius: 10px;
  overflow: hidden;
  border: 1.5px solid var(--border);
  background: var(--surface);
}
.attach-card-image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.attach-card-image .attach-card-noimg {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.6rem;
  opacity: .5;
}
.attach-card-image[data-expired="1"] {
  opacity: .55;
  border-style: dashed;
}
.attach-card-doc {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  max-width: 220px;
  padding: 8px 12px;
  border-radius: 10px;
  border: 1.5px solid var(--border);
  background: var(--surface);
}
.attach-card-doc[data-expired="1"] { opacity: .6; border-style: dashed; }
.attach-card-icon { flex-shrink: 0; color: var(--primary); }
.attach-card-info { min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.attach-card-name {
  font-size: .78rem;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.attach-card-meta {
  font-size: .68rem;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Drag-and-drop overlay lives at #drop-overlay (scoped to .chat-messages) —
   see assets/js/dashboard.js's "Drag-and-drop file attach" block. A second,
   page-wide implementation used to live here (.drag-overlay / #drag-overlay)
   and fired alongside it on every drop since both listeners saw the same
   bubbling event, which is why a dropped file was attached twice. Removed
   rather than merged — the scoped version was already the complete, more
   recent implementation (mode-aware via _routeAttachment). */

/* ── Char counter warning/danger ────────────────────────────────── */
.char-counter.warn   { color: #f59e0b !important; font-weight: 700; }
.char-counter.danger { color: #ef4444 !important; font-weight: 700; animation: counterPulse .4s ease; }
@keyframes counterPulse {
  0%, 100% { transform: scale(1); }
  50%       { transform: scale(1.15); }
}

/* ── Draft indicator (subtle) ───────────────────────────────────── */
.draft-dot {
  display: inline-block;
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--primary);
  opacity: 0;
  transition: opacity .3s;
  vertical-align: middle;
  margin-left: 4px;
}
.draft-dot.visible { opacity: .7; }

/* Hint */
/* Add streaming class toggle via JS */

/* -- Textarea padding fix -- */
#chat-input {
  padding: 14px 16px 12px 16px !important;
}

/* Also give the card itself a tiny top breathing room */
.composer-card {
  margin-bottom: 2px;
}

/* -- Model pill - shaded so it reads as the active model indicator -- */
.composer-model-pill {
  background: color-mix(in srgb, var(--primary) 8%, transparent) !important;
  border: 1px solid color-mix(in srgb, var(--primary) 20%, transparent) !important;
  border-radius: 8px !important;
  padding: 4px 10px !important;
  gap: 6px !important;
  transition: background .18s, border-color .18s !important;
}
.composer-model-pill:hover {
  background: color-mix(in srgb, var(--primary) 15%, transparent) !important;
  border-color: color-mix(in srgb, var(--primary) 35%, transparent) !important;
}
.composer-model-pill svg {
  color: var(--primary) !important;
}
.composer-model-select {
  color: var(--primary) !important;
  font-weight: 700 !important;
  font-size: .8rem !important;
}

@media (max-width: 600px) {
  .btn-label-hide-mobile { display: none !important; }
}

/* -- Mobile top bar -- */
.mobile-topbar {
  display: none;
  align-items: center;
  justify-content: space-between;
  padding: 10px 14px;
  background: var(--topbar-bg);
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
  z-index: 10;
  gap: 10px;
}

/* Desktop sidebar toggle button - always visible */
.sidebar-toggle-btn {
  width: 34px; height: 34px;
  display: flex; align-items: center; justify-content: center;
  background: none;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  color: var(--muted);
  transition: background .15s, color .15s;
  flex-shrink: 0;
}
.sidebar-toggle-btn:hover { background: var(--bg); color: var(--text); }

/* Sidebar transition */
.app-sidebar {
  transition: width .25s cubic-bezier(.16,1,.3,1), min-width .25s;
}

/* Collapsed state - desktop */
.app-shell.sidebar-collapsed .app-sidebar {
  width: 0 !important;
  min-width: 0 !important;
  overflow: hidden;
}
.app-shell.sidebar-collapsed .app-main {
  max-width: 100vw !important;
}

/* Show sidebar floating button - only when collapsed */
.sidebar-show-btn {
  display: none;
  position: fixed;
  top: 12px;
  left: 12px;
  z-index: 50;
  width: 36px; height: 36px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 9px;
  box-shadow: 0 2px 8px rgba(0,0,0,.1);
  cursor: pointer;
  align-items: center;
  justify-content: center;
  color: var(--muted);
  transition: background .15s, color .15s, box-shadow .15s;
}
.sidebar-show-btn:hover { background: var(--bg); color: var(--text); box-shadow: 0 4px 12px rgba(0,0,0,.15); }
.app-shell.sidebar-collapsed .sidebar-show-btn { display: flex; }

.mobile-topbar-title {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: .95rem;
  font-weight: 700;
  color: var(--text);
}

.mobile-menu-btn,
.mobile-new-chat-btn {
  width: 38px; height: 38px;
  display: flex; align-items: center; justify-content: center;
  background: none;
  border: none;
  border-radius: 10px;
  cursor: pointer;
  color: var(--text);
  transition: background .18s;
  flex-shrink: 0;
}
.mobile-menu-btn:hover,
.mobile-new-chat-btn:hover { background: var(--border); }

/* Sidebar backdrop */
.sidebar-backdrop {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,.45);
  backdrop-filter: blur(3px);
  z-index: 49;
  opacity: 0;
  transition: opacity .3s ease;
  cursor: pointer;                        /* iOS Safari: click fires only on elements with cursor:pointer */
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}
.sidebar-backdrop.show {
  display: block;
  opacity: 1;
}

@media (max-width: 768px) {
  .mobile-topbar { display: flex !important; }

  /* Sidebar slides in from left */
  .app-sidebar {
    position: fixed !important;
    left: 0; top: 0;
    height: 100dvh;
    z-index: 100;
    transform: translateX(-100%);
    transition: transform .3s cubic-bezier(.16,1,.3,1);
    box-shadow: none;
  }
  .app-sidebar.open {
    transform: translateX(0) !important;
    box-shadow: 6px 0 32px rgba(0,0,0,.25) !important;
  }

  /* Main takes full width on mobile */
  .app-main {
    max-width: 100vw !important;
    width: 100vw !important;
  }
}

/* ========================================
   MOBILE OPTIMIZATIONS (≤768px)
   ======================================== */

@media (max-width: 768px) {

  /* -- Layout -- */
  .app-layout { flex-direction: column !important; height: 100dvh !important; overflow: hidden !important; }
  .app-main { flex: 1 !important; min-height: 0 !important; display: flex !important; flex-direction: column !important; overflow: hidden !important; }
  .chat-messages { flex: 1 !important; overflow-y: auto !important; -webkit-overflow-scrolling: touch !important; padding: 12px 12px 8px !important; overscroll-behavior: contain !important; }

  /* -- Mobile top bar -- */
  .mobile-topbar { display: flex !important; padding: 8px 10px !important; min-height: 52px !important; position: fixed !important; top: 0 !important; left: 0 !important; right: 0 !important; z-index: 99 !important; box-shadow: 0 1px 8px rgba(0,0,0,.08) !important; }
  /* padding-top removed: .app-main is now position:fixed;top:calc(52px+safe-area) so no internal offset needed */
  .mobile-topbar-actions { display: flex; align-items: center; gap: 2px; }
  .mobile-icon-btn { width: 40px; height: 40px; display: flex; align-items: center; justify-content: center; background: none; border: none; cursor: pointer; border-radius: 10px; color: var(--text); transition: background .18s; text-decoration: none; -webkit-tap-highlight-color: transparent; }
  .mobile-icon-btn:hover, .mobile-icon-btn:active { background: var(--border); }

  /* -- Sidebar -- */
  /* The sidebar itself must NEVER scroll — it's a fixed-height flex column
     whose #session-list child is the only scrolling part (see the
     max-width:768px block further down, which sets display:flex +
     overflow:hidden on this same element). This rule used to also set
     `overflow-y: auto !important` here, which made the whole sidebar a
     scroll container: header, search and footer scrolled away with the
     list, so a long chat list read as "the session list is the only thing
     I can see". The later block's `overflow: hidden` happened to win on
     source order, but leaving the contradiction in place meant any
     reordering of this file would silently reintroduce the bug. */
  .app-sidebar { position: fixed !important; left: 0 !important; top: 0 !important; height: 100dvh !important; width: 82vw !important; max-width: 320px !important; z-index: 100 !important; transform: translateX(-100%) !important; transition: transform .3s cubic-bezier(.16,1,.3,1) !important; box-shadow: none !important; display: flex !important; flex-direction: column !important; overflow: hidden !important; overscroll-behavior: contain !important; }
  .app-sidebar.open { transform: translateX(0) !important; box-shadow: 8px 0 40px rgba(0,0,0,.28) !important; }

  /* Sidebar backdrop */
  .sidebar-backdrop { position: fixed; inset: 0; background: rgba(0,0,0,.5); backdrop-filter: blur(2px); -webkit-backdrop-filter: blur(2px); z-index: 99; opacity: 0; transition: opacity .3s ease; display: none; cursor: pointer; -webkit-tap-highlight-color: transparent; touch-action: manipulation; }
  .sidebar-backdrop.show { display: block; opacity: 1; }

  /* -- Composer on mobile -- */
  .chat-input-wrap { padding: 6px 8px max(8px, env(safe-area-inset-bottom)) !important; }
  .composer-card { border-radius: 16px !important; }
  #chat-input { font-size: 16px !important; min-height: 44px !important; }

  /* Toolbar: single row, overflow scrolls so nothing is hidden */
  .composer-toolbar { padding: 4px 8px 6px !important; flex-wrap: nowrap !important; gap: 2px !important; overflow: hidden !important; }
  .composer-tools-left { overflow-x: auto !important; overflow-y: hidden !important; flex-shrink: 1 !important; flex-wrap: nowrap !important; gap: 1px !important; scrollbar-width: none !important; -webkit-overflow-scrolling: touch !important; }
  .composer-tools-left::-webkit-scrollbar { display: none !important; }
  .composer-tools-right { flex-shrink: 0 !important; margin-left: 6px !important; }

  /* Bigger touch targets */
  .composer-tool-btn { padding: 8px 10px !important; min-height: 36px !important; -webkit-tap-highlight-color: transparent !important; }
  .composer-model-pill { min-height: 36px !important; padding: 4px 8px !important; flex-shrink: 0 !important; }
  .composer-model-select { max-width: 100px !important; font-size: .75rem !important; }
  .composer-temp-pill { padding: 4px 8px !important; min-height: 36px !important; }
  .composer-temp-pill input[type=range] { width: 48px !important; }
  .send-btn { width: 38px !important; height: 38px !important; border-radius: 10px !important; flex-shrink: 0 !important; }
  .char-counter { display: none !important; }

  /* -- Messages -- */
  /* (superseded by the fuller .msg-user/.msg-ai split further down, which
     keeps AI responses full-width for readability — kept in sync here so
     this earlier declaration doesn't reintroduce the AI-message gap.) */
  .msg-user { max-width: 92% !important; margin-left: auto !important; }
  .msg-ai   { max-width: 100% !important; width: 100% !important; }
  .msg-content { font-size: .9rem !important; }
  pre { font-size: .78rem !important; overflow-x: auto !important; }
  code { font-size: .78rem !important; }

  /* -- Welcome screen -- */
  .welcome-screen { padding: 24px 16px 16px !important; gap: 8px !important; }
  .welcome-screen h2 { font-size: 1.2rem !important; }
  .welcome-chips { gap: 6px !important; }
  .chip { padding: 7px 12px !important; font-size: .8rem !important; }

  /* -- Mobile session title -- */
  #mobile-session-title { max-width: 140px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: .85rem; }

  /* Hide manual hide-button — auto-hide replaces it on mobile */
  #composer-toggle-btn { display: none !important; }
  /* Hide "Switch to Full Compose" — compact is locked on mobile */
  #mts-mode-toggle { display: none !important; }
}

/* -- Shortcut Picker -- */
.sc-picker {
  position: absolute;
  bottom: calc(100% + 8px);
  left: 14px; right: 14px;
  background: var(--surface);
  border: 1.5px solid var(--primary);
  border-radius: 14px;
  box-shadow: 0 8px 32px rgba(0,0,0,.15);
  z-index: 500;
  overflow: hidden;
  animation: scPickerIn .18s cubic-bezier(.16,1,.3,1);
  max-height: 320px;
  display: flex;
  flex-direction: column;
}
@keyframes scPickerIn {
  from { opacity:0; transform: translateY(8px) scale(.97); }
  to   { opacity:1; transform: none; }
}
.sc-picker-header {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 9px 14px 7px;
  font-size: .73rem;
  font-weight: 600;
  color: var(--primary);
  border-bottom: 1px solid var(--border);
  letter-spacing: .04em;
  text-transform: uppercase;
  background: color-mix(in srgb, var(--primary) 5%, transparent);
}
.sc-picker-list {
  overflow-y: auto;
  max-height: 220px;
  padding: 6px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.sc-picker-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 10px;
  border-radius: 9px;
  cursor: pointer;
  transition: background .12s;
}
.sc-picker-item:hover,
.sc-picker-item.active {
  background: color-mix(in srgb, var(--primary) 10%, transparent);
}
.sc-picker-item .sc-tag {
  font-size: .8rem;
  font-weight: 700;
  font-family: monospace;
  color: var(--primary);
  background: color-mix(in srgb, var(--primary) 10%, transparent);
  padding: 2px 8px;
  border-radius: 5px;
  white-space: nowrap;
  min-width: 60px;
}
/* Type/preset badge (🎨/🎬/🔊/🔒) — deliberately NOT .sc-tag: that class's
   min-width:60px is sized for the "/shortcut" chip's text and left a large
   blank gap after a single-emoji badge when reused here. */
.sc-picker-item .sc-type-badge {
  font-size: .8rem;
  padding: 2px 6px;
  border-radius: 5px;
  line-height: 1.4;
  flex-shrink: 0;
}
.sc-picker-item .sc-name {
  font-size: .85rem;
  font-weight: 600;
  color: var(--text);
  flex-shrink: 0;
}
.sc-picker-item .sc-desc {
  font-size: .78rem;
  color: var(--muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  flex: 1;
}
.sc-picker-footer {
  padding: 7px 14px;
  border-top: 1px solid var(--border);
  font-size: .72rem;
}
.sc-picker-footer a {
  color: var(--muted);
  text-decoration: none;
}
.sc-picker-footer a:hover { color: var(--primary); }

/* Relative wrapper so picker positions correctly */
.chat-input-wrap { position: relative; }

/* ── Typing indicator ─────────────────────────────────────────── */
.typing-indicator {
  display: flex;
  align-items: center;
  gap: 5px;
  padding: 4px 2px;
}
.typing-indicator .dot {
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--primary);
  opacity: .4;
  animation: typingBounce 1.8s ease-in-out infinite;
  flex-shrink: 0;
  display: inline-block;
}
.typing-indicator .dot:nth-child(2) { animation-delay: .25s; }
.typing-indicator .dot:nth-child(3) { animation-delay: .5s; }
@keyframes typingBounce {
  0%, 60%, 100% { transform: translateY(0) scale(.85); opacity: .4; }
  30%           { transform: translateY(-6px) scale(1); opacity: 1; }
}
.typing-label {
  display: inline-flex;
  align-items: baseline;
  font-size: .82rem;
  font-weight: 600;
  color: var(--primary);
  margin-left: 4px;
  min-width: 0;
  opacity: 1;
  filter: blur(0);
}
/* Natural (non-fixed) width — same as the extension's own .typing-label
   (extension/sidepanel.css), which is what the bubble-grows-with-the-text
   effect this mirrors actually comes from: .msg-bubble-thinking below drops
   its own width to fit-content, so as this text is typed in/out the whole
   card visibly grows and shrinks with it instead of sitting at a fixed
   width. The empty-string flicker a truly-fixed width used to guard against
   (see typeNext() in dashboard.js) is instead avoided at the source: it
   always writes a non-breaking space, never '', so there's no zero-width
   frame to jump from. Width changes are additionally smoothed by
   .msg-bubble-thinking's own transition, so this never reads as a snap. */
.typing-text {
  display: inline-block;
  white-space: nowrap;
  vertical-align: bottom;
}
/* While the placeholder is showing, the bubble hugs the dots+phrase instead
   of stretching to the message column's full width (.msg-bubble's normal
   flex-stretch layout, from app.css) — same shrink-wrapped-card feel as the
   extension's own thinking bubble. dashboard.js removes this class the
   moment real content arrives (_stopTypingRotation()), handing the bubble
   back to its normal full-width layout for the actual reply. The transition
   is what keeps phrase-length changes from ever reading as a snap/jump. */
.msg-bubble-thinking {
  align-self: flex-start;
  width: fit-content;
  max-width: min(80vw, 340px);
  transition: width .22s ease;
}
.typing-label.typing-fade-out {
  animation: typingFadeOut var(--typing-fade-ms, .26s) ease forwards;
}
.typing-label.typing-fade-in {
  animation: typingFadeIn var(--typing-fade-ms, .26s) ease forwards;
}
/* Pure fade — no vertical shift. A slide read oddly against left-to-right
   text (it looked like the words were sliding up off the line instead of
   just vanishing), so the exit/entry is opacity+blur only now. */
@keyframes typingFadeOut {
  0%   { opacity: 1; filter: blur(0); }
  100% { opacity: 0; filter: blur(3px); }
}
@keyframes typingFadeIn {
  0%   { opacity: 0; filter: blur(3px); }
  100% { opacity: 1; filter: blur(0); }
}
@keyframes typingFade {
  0%, 100% { opacity: .5; }
  50%      { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .typing-label.typing-fade-out,
  .typing-label.typing-fade-in { animation: none; }
}
/* Credit deduction feedback on the sidebar balance badge */
@keyframes creditPulse {
  0%   { transform: scale(1); }
  35%  { transform: scale(1.18); }
  100% { transform: scale(1); }
}
.credit-badge.charging { animation: creditPulse .5s ease; }
.credit-float {
  position: absolute;
  top: -12px;
  right: 4px;
  font-size: .66rem;
  font-weight: 700;
  color: #dc2626;
  pointer-events: none;
  white-space: nowrap;
  animation: creditFloat 1.1s ease forwards;
}
[data-theme="dark"] .credit-float { color: #f87171; }
@keyframes creditFloat {
  0%   { opacity: 0; transform: translateY(2px); }
  25%  { opacity: 1; }
  100% { opacity: 0; transform: translateY(-16px); }
}
/* Theme the sidebar credit badge like the ghost tool buttons next to it
   (transparent + muted), with a subtle border to keep it reading as a badge.
   The red low-balance state (.low) is left untouched via :not(.low). */
#credit-badge-sidebar {
  border: none !important;
  border-radius: 7px !important;
  font-weight: 600 !important;
  gap: 5px !important;
  transition: background .15s, color .15s;
}
#credit-badge-sidebar:not(.low) {
  background: transparent !important;
  color: var(--text) !important;
}
/* Same hover feedback as the Persona/Memory ghost buttons next to it —
   .btn-ghost:hover (background: var(--bg); color: var(--text)) PLUS the
   global .btn:hover brightness dip (see the (hover: hover) media rule
   above) that those buttons also pick up via their shared .btn class;
   without it the badge's hover reads visibly lighter/weaker than theirs. */
#credit-badge-sidebar:not(.low):hover {
  background: var(--bg) !important;
  color: var(--text) !important;
}
@media (hover: hover) and (pointer: fine) {
  #credit-badge-sidebar:not(.low):hover { filter: brightness(.94); }
}
#credit-badge-sidebar.low:hover { filter: brightness(.93); }
#credit-badge-sidebar .cbs-icon { flex-shrink: 0; opacity: .85; }
/* The number text needs its own shrink target — without min-width:0 a flex
   item won't shrink below its content size, so a long balance just pushes
   the badge wider instead of truncating inside it. */
#credit-badge-sidebar .cbs-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Single collapsible activity ("Thoughts") panel — holds tool activity lines
   (e.g. "Searching the web…") AND the streamed reasoning, in one box. */
.reasoning-panel {
  margin: 4px 0 8px;
  border: 1px solid color-mix(in srgb, var(--primary) 20%, transparent);
  border-radius: 10px;
  background: color-mix(in srgb, var(--primary) 6%, transparent);
  overflow: hidden;
  font-size: .82rem;
}
.reasoning-panel > summary {
  cursor: pointer;
  list-style: none;
  user-select: none;
  display: flex;
  align-items: center;
  gap: 6px;
  min-height: 36px;
  box-sizing: border-box;
  padding: 8px 12px;
  font-weight: 600;
  color: var(--primary);
}
.reasoning-panel > summary::-webkit-details-marker { display: none; }
.reasoning-panel[data-streaming="1"] > summary { animation: typingFade 1.8s ease-in-out infinite; }
.reasoning-panel > summary .rp-chev {
  margin-left: auto;
  transition: transform .2s ease;
  opacity: .7;
}
.reasoning-panel[open] > summary .rp-chev { transform: rotate(180deg); }
.reasoning-body {
  border-top: 1px solid color-mix(in srgb, var(--primary) 12%, transparent);
  max-height: 360px;
  overflow-y: auto;
}
/* Tool activity lines (web search, etc.) */
.rp-act-line {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 8px 12px;
  font-size: .8rem;
  font-weight: 500;
  color: var(--primary);
}
.rp-act-line.streaming { animation: typingFade 1.8s ease-in-out infinite; }
.rp-act-line.done { opacity: .55; }
/* Streamed chain-of-thought text */
.reasoning-content {
  padding: 8px 12px 10px;
  color: var(--text-muted, #8a8a93);
  font-size: .8rem;
  line-height: 1.6;
  white-space: pre-wrap;
  word-break: break-word;
}
/* Separator only when both activity lines and thoughts text are present */
.rp-activity:not(:empty) + .reasoning-content:not(:empty) {
  border-top: 1px solid color-mix(in srgb, var(--primary) 12%, transparent);
}
.reasoning-content:empty { display: none; }

/* ── Code blocks ──────────────────────────────────────────────── */
.code-block-wrap {
  margin: 10px 0;
  border-radius: 10px;
  overflow: hidden;
  border: 1px solid rgba(255,255,255,.09);
  background: #1e1e2e;
}
.code-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 8px 14px;
  background: #161625;
  border-bottom: 1px solid rgba(255,255,255,.07);
  position: sticky;
  top: 0;
  z-index: 2;
}
.code-header-actions { display: flex; align-items: center; gap: 6px; }
.code-wrap-btn {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  background: rgba(255,255,255,.07);
  border: 1px solid rgba(255,255,255,.1);
  color: rgba(255,255,255,.5);
  border-radius: 5px;
  padding: 3px 8px;
  font-size: .71rem;
  cursor: pointer;
  transition: background .15s, color .15s;
  font-family: inherit;
  white-space: nowrap;
}
.code-wrap-btn:hover { background: rgba(255,255,255,.13); color: #fff; }
.code-wrap-btn.active { background: var(--primary); color: #fff; border-color: var(--primary); }
.code-wrap-btn svg { flex-shrink: 0; }
.code-block-wrap.soft-wrap pre,
.code-block-wrap.soft-wrap pre code {
  white-space: pre-wrap !important;
  word-break: break-word !important;
  overflow-x: hidden !important;
}
.code-lang {
  font-size: .7rem;
  font-weight: 700;
  color: rgba(255,255,255,.38);
  text-transform: uppercase;
  letter-spacing: .1em;
  font-family: 'Fira Code', 'Consolas', monospace;
}
.code-copy-btn, .code-save-btn {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  background: rgba(255,255,255,.07);
  border: 1px solid rgba(255,255,255,.1);
  color: rgba(255,255,255,.5);
  border-radius: 5px;
  padding: 3px 10px;
  font-size: .71rem;
  cursor: pointer;
  transition: background .15s, color .15s;
  font-family: inherit;
  white-space: nowrap;
}
.code-copy-btn:hover, .code-save-btn:hover { background: rgba(255,255,255,.13); color: #fff; }
.code-copy-btn svg, .code-save-btn svg { flex-shrink: 0; }
/* Three action buttons (Wrap/Copy/Save) no longer fit their text labels on
   narrow phones inside .code-block-wrap's clipped (overflow:hidden) header —
   collapse to icon-only there; the title/aria-label attributes keep them
   labeled for tooltips and screen readers. */
@media (max-width: 480px) {
  .cha-label { display: none; }
  .code-wrap-btn, .code-copy-btn, .code-save-btn { padding: 4px 7px; }
}
/* Pre inside the wrapper */
.code-block-wrap pre {
  margin: 0 !important;
  border-radius: 0 !important;
  padding: 14px 16px !important;
  overflow-x: auto !important;
  font-size: .84rem !important;
  line-height: 1.65 !important;
  background: #1e1e2e !important;
  border: none !important;
}
.code-block-wrap pre code {
  background: none !important;
  padding: 0 !important;
  border: none !important;
  font-size: inherit !important;
  border-radius: 0 !important;
  white-space: pre !important;
  display: block !important;
}
/* Inline code */
.msg-bubble code:not(pre code) {
  background: rgba(0,0,0,.07);
  color: var(--text);
  padding: 2px 6px;
  border-radius: 4px;
  border: 1px solid rgba(0,0,0,.09);
  font-size: .84em;
  font-family: 'Fira Code', 'Consolas', monospace;
}
[data-theme="dark"] .msg-bubble code:not(pre code) {
  background: rgba(255,255,255,.08);
  border-color: rgba(255,255,255,.1);
  color: #e2e8f0;
}

/* ── NEW: Edit user message ──────────────────────────────── */
.msg-edit-btn {
  display: none;
  background: none; border: none; cursor: pointer;
  color: var(--muted); padding: 3px 6px; border-radius: 5px;
  font-size: .72rem; align-items: center; gap: 4px;
  transition: background .15s, color .15s;
}
.msg-user:hover .msg-edit-btn { display: inline-flex; }
.msg-edit-btn:hover { background: var(--bg); color: var(--primary); }
.msg-pin-btn {
  display: none;
  background: none; border: none; cursor: pointer;
  color: var(--muted); padding: 3px 6px; border-radius: 5px;
  font-size: .72rem; align-items: center; gap: 4px;
  transition: background .15s, color .15s;
}
.msg:hover .msg-pin-btn { display: inline-flex; }
.msg-pin-btn:hover { background: var(--bg); color: var(--primary); }
.msg-pin-btn.active { display: inline-flex; color: #f59e0b; }
.msg-pin-btn.active svg { fill: currentColor; }
.pinned-item {
  display: flex; flex-direction: column; gap: 4px;
  padding: 10px 12px; border-radius: 10px; border: 1px solid var(--border);
  margin-bottom: 8px;
}
.pinned-item-meta { display: flex; justify-content: space-between; align-items: center; gap: 8px; font-size: .72rem; color: var(--muted); }
.pinned-item-text { font-size: .85rem; line-height: 1.5; white-space: pre-wrap; word-break: break-word; }
.pinned-item-actions { display: flex; gap: 6px; }
.pinned-empty { padding: 24px; text-align: center; color: var(--muted); font-size: .85rem; }
.msg-edit-area {
  width: 100%; font-size: .9rem; font-family: inherit;
  border: 1.5px solid var(--primary); border-radius: 10px;
  padding: 8px 10px; resize: vertical; min-height: 60px;
  background: var(--bg); color: var(--text); outline: none;
  margin-bottom: 6px;
}
.msg-edit-actions { display: flex; gap: 6px; justify-content: flex-end; margin-bottom: 6px; }

/* Phase 60 — AI response version nav */
.msg-version-nav { display: inline-flex; align-items: center; gap: 4px; }
.msg-version-nav .copy-btn { padding: 3px 5px; }
.msg-version-nav .copy-btn:disabled { opacity: .35; cursor: default; }
.msg-version-label { font-size: .72rem; color: var(--muted); min-width: 28px; text-align: center; }
.msg-edited-badge {
  background: none; border: none; cursor: pointer;
  color: var(--muted); font-size: .72rem; padding: 3px 6px; border-radius: 5px;
  transition: background .15s, color .15s;
}
.msg-edited-badge:hover { background: var(--bg); color: var(--primary); }

/* E4 — Branch button */
.msg-branch-btn {
  display: none;
  background: none; border: none; cursor: pointer;
  color: var(--muted); padding: 3px 6px; border-radius: 5px;
  font-size: .72rem; align-items: center; gap: 4px;
  transition: background .15s, color .15s;
}
.msg-user:hover .msg-branch-btn { display: inline-flex; }
.msg-branch-btn:hover { background: var(--bg); color: #7c3aed; }
.msg-branch-btn:disabled { opacity: .5; cursor: not-allowed; }

/* ── Composer modes: docked (default) / focus ───────────────────────────── */

/* Peek bar permanently removed — kept in DOM for PHP back-compat, always hidden */
.composer-peek-bar { display: none !important; }

/* ── Compose FAB — shown when composer is collapsed (swipe-down or Focus
   mode). Anchored bottom-RIGHT rather than centered — the "scroll to
   bottom" pill lives centered in this same bottom strip, so a centered FAB
   would sit directly on top of it once the composer collapses to 0 height. */
#composer-show-fab {
  display: none;
  position: fixed;
  bottom: max(22px, env(safe-area-inset-bottom, 22px));
  right: max(16px, calc(env(safe-area-inset-right, 0px) + 16px));
  width: 44px; height: 44px;
  border-radius: 50%;
  background: var(--primary);
  color: #fff;
  border: none;
  box-shadow: 0 4px 18px color-mix(in srgb, var(--primary) 50%, transparent), 0 2px 6px rgba(0,0,0,.18);
  align-items: center; justify-content: center;
  cursor: pointer; z-index: 200;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  transition: transform .15s, box-shadow .15s;
}
#composer-show-fab svg { width: 18px; height: 18px; }
#composer-show-fab:active {
  transform: scale(.9);
  box-shadow: 0 2px 10px color-mix(in srgb, var(--primary) 40%, transparent);
}

/* ── One-time swipe-down hint (mobile) ─────────────────────────────────── */
#composer-swipe-hint {
  position: absolute;
  right: 10px;
  bottom: 100%;
  margin-bottom: 8px;
  display: none;
  align-items: center;
  gap: 6px;
  max-width: 180px;
  padding: 6px 8px 6px 10px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: 0 4px 16px rgba(0,0,0,.15);
  font-size: .7rem;
  color: var(--text);
  z-index: 60;
}
#composer-swipe-hint.show { display: flex; }
#composer-swipe-hint button {
  flex-shrink: 0;
  display: flex;
  background: none;
  border: none;
  padding: 2px;
  color: var(--muted);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

/* ── Brief "Draw/Video/Audio mode" badge (mobile only) ─────────────────── */
#mode-switch-toast {
  display: none;
  position: absolute;
  left: 50%;
  bottom: 100%;
  margin-bottom: 8px;
  transform: translateX(-50%) translateY(4px);
  align-items: center;
  gap: 6px;
  padding: 7px 14px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 99px;
  box-shadow: 0 4px 16px rgba(0,0,0,.15);
  font-size: .78rem;
  font-weight: 600;
  color: var(--primary);
  white-space: nowrap;
  z-index: 60;
  opacity: 0;
  pointer-events: none;
  transition: opacity .18s ease, transform .18s ease;
}
#mode-switch-toast.show {
  display: flex;
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}
@media (min-width: 769px) {
  #mode-switch-toast { display: none !important; }
}

@media (max-width: 768px) {
  /* Composer collapsed — via swipe-down or Focus mode's own auto-collapse */
  .app-main.composer-collapsed .chat-input-wrap {
    max-height: 0 !important;
    overflow: hidden !important;
    padding: 0 !important;
    margin: 0 !important;
    border: none !important;
    box-shadow: none !important;
    pointer-events: none !important;
  }
  .app-main.composer-collapsed #composer-show-fab { display: flex !important; }
  .app-main.composer-collapsed #composer-swipe-hint { display: none !important; }

  /* Last message body needs space so it isn't hidden behind the compose FAB */
  .app-main.composer-collapsed .chat-messages .msg:last-child .msg-body {
    margin-bottom: 70px;
  }

}

/* ── Searchable model picker dialog ────────────────────────── */
.model-picker-overlay {
  display: none; position: fixed; inset: 0; z-index: 1600;
  align-items: center; justify-content: center;
}
.model-picker-overlay.open { display: flex; }
.model-picker-backdrop {
  position: absolute; inset: 0;
  background: rgba(0,0,0,.42);
  -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
}
.model-picker-dialog {
  position: relative; z-index: 1;
  width: 440px; max-width: calc(100vw - 32px);
  max-height: 70vh; display: flex; flex-direction: column;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 14px; box-shadow: 0 12px 48px rgba(0,0,0,.25);
  overflow: hidden;
}
.model-picker-header {
  display: flex; align-items: center; gap: 8px;
  padding: 10px 12px; border-bottom: 1px solid var(--border);
  color: var(--muted); flex-shrink: 0;
}
#model-picker-search {
  flex: 1; border: none; background: none; outline: none;
  font-size: .9rem; color: var(--text); font-family: inherit;
}
.model-picker-close {
  background: none; border: none; cursor: pointer;
  color: var(--muted); font-size: .85rem; padding: 2px 4px;
}
.model-picker-list { overflow-y: auto; padding: 6px; }
.mp-group-label {
  padding: 8px 10px 4px; font-size: .7rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .04em; color: var(--muted);
}
.mp-item {
  display: flex; align-items: center; justify-content: flex-start; gap: 8px; width: 100%;
  text-align: left; padding: 9px 10px; border-radius: 8px;
  background: none; border: none; cursor: pointer;
  font-size: .86rem; color: var(--text); font-family: inherit;
}
.mp-item:hover { background: var(--bg); }
.mp-item.active { background: color-mix(in srgb, var(--primary) 12%, transparent); color: var(--primary); font-weight: 600; }
/* text-align set explicitly (not just inherited from .mp-item) — the Draw/
   Video/Audio model pills' rows (_renderGenericPickerList()) have no
   .mp-item-badges sibling to anchor to the right, so this label is the last
   flex child; without its own text-align it rendered centered in some
   browsers instead of left, unlike text mode's 3-child row. */
.mp-item-label { flex: 1; text-align: left; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Provider/model glyph — used in the composer/draw/video/audio model pills
   and every row of the searchable model picker (see includes/provider_icons.php,
   includes/model_icons.php, dashboard.php providerIconHtml()/modelIconHtml()). */
.model-icon { display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; width: 13px; height: 13px; }
.model-icon svg, .model-icon img { width: 100%; height: 100%; object-fit: contain; display: block; }
.mp-item .model-icon { width: 16px; height: 16px; }
.mp-item-badges { flex-shrink: 0; font-size: .8rem; opacity: .8; display: inline-flex; align-items: center; gap: 2px; }
/* Matches .mp-reasoning-icon's SVG stroke treatment (bold, crisp) instead of
   a thin emoji glyph. */
.mp-zdr-badge {
  display: inline-flex; vertical-align: -1px; cursor: help;
  color: #059669;
}
/* ZDR shield on the model pill — matches .pill-reasoning-icon's SVG stroke
   treatment (bold, crisp) instead of a thin emoji glyph. */
.composer-model-pill .pill-zdr-shield { display: inline-flex; margin-left: 3px; color: #059669; vertical-align: -1px; }
/* Reasoning-capable icon on the model pill */
.composer-model-pill .pill-reasoning-icon { display: inline-flex; margin-left: 3px; color: var(--primary); vertical-align: -1px; }
/* Reasoning-capable icon in the model picker list */
.mp-item-badges .mp-reasoning-icon { display: inline-block; vertical-align: -1px; color: var(--primary); }
.mp-empty { padding: 24px; text-align: center; color: var(--muted); font-size: .85rem; }
@media (max-width: 768px) {
  .model-picker-overlay { align-items: flex-end; }
  .model-picker-dialog {
    width: 100%; max-width: 100%; max-height: 75vh;
    border-radius: 16px 16px 0 0;
    padding-bottom: env(safe-area-inset-bottom, 0px);
  }
  #model-picker-search { font-size: 16px; }
}

/* ── Toast notifications — base styles moved to ui.css (shared kit).
      dashboard.css keeps nothing extra; #toast-stack markup lives in
      dashboard.php and positioning comes from ui.css. ── */

/* ── Drag-and-drop image overlay ───────────────────────────── */
#chat-messages { position: relative; }
#drop-overlay {
  display: none; position: absolute; inset: 0; z-index: 30;
  align-items: center; justify-content: center; flex-direction: column; gap: 8px;
  background: color-mix(in srgb, var(--primary) 8%, var(--bg));
  border: 2px dashed var(--primary);
  border-radius: 12px; margin: 8px;
  color: var(--primary); font-size: .95rem; font-weight: 600;
  pointer-events: none;
}
#drop-overlay.visible { display: flex; }
#drop-overlay svg { opacity: .8; }

/* ── Out-of-credits banner ─────────────────────────────────── */
.empty-credit-banner {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 14px; flex-shrink: 0;
  background: color-mix(in srgb, var(--danger, #ef4444) 10%, transparent);
  border-top: 1px solid color-mix(in srgb, var(--danger, #ef4444) 25%, transparent);
  color: var(--danger, #ef4444);
  font-size: .85rem;
}
.empty-credit-banner span { flex: 1; }
.empty-credit-banner svg { flex-shrink: 0; }
@media (max-width: 768px) {
  .empty-credit-banner { flex-wrap: wrap; padding: 8px 12px; font-size: .8rem; }
}

/* ── Reduced motion ─────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}
body.reduced-motion *, body.reduced-motion *::before, body.reduced-motion *::after {
  animation-duration: 0.001ms !important;
  animation-iteration-count: 1 !important;
  transition-duration: 0.001ms !important;
  scroll-behavior: auto !important;
}

/* ── Split / multi-pane view (desktop) ─────────────────── */
.split-pane {
  display: none;
  position: fixed;
  top: 0; right: 0; bottom: 0;
  width: 42vw; min-width: 340px; max-width: 680px;
  z-index: 80;
  background: var(--surface);
  border-left: 1px solid var(--border);
  box-shadow: -8px 0 28px rgba(0,0,0,.10);
  flex-direction: column;
}
.split-pane.open { display: flex; animation: splitPaneIn .25s cubic-bezier(.16,1,.3,1); }
body.reduced-motion .split-pane.open { animation: none; }
@keyframes splitPaneIn { from { transform: translateX(24px); opacity: 0; } to { transform: none; opacity: 1; } }
.split-pane-header {
  display: flex; align-items: center; gap: 8px;
  padding: 10px 12px;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}
.split-pane-header select {
  flex: 1; min-width: 0;
  padding: 7px 10px;
  border: 1.5px solid var(--border); border-radius: 8px;
  background: var(--bg); color: var(--text);
  font-size: .85rem; font-family: inherit;
}
.split-pane-close {
  flex-shrink: 0;
  background: none; border: 1px solid var(--border); border-radius: 8px;
  width: 32px; height: 32px;
  display: flex; align-items: center; justify-content: center;
  color: var(--muted); cursor: pointer;
}
.split-pane-close:hover { background: var(--bg); color: var(--text); }
.split-pane-frame { flex: 1; width: 100%; border: none; background: var(--bg); }
body.split-view-active .app-main { margin-right: 42vw; }
@media (max-width: 1100px) {
  .split-pane { display: none !important; }
  body.split-view-active .app-main { margin-right: 0 !important; }
}
/* Embedded (iframe) view — hide chrome that doesn't make sense in a side pane */
html.embed-mode .app-sidebar,
html.embed-mode .sidebar-show-btn,
html.embed-mode .mobile-topbar,
html.embed-mode .sidebar-backdrop {
  display: none !important;
}
html.embed-mode .app-main { max-width: 100% !important; margin-right: 0 !important; }

/* ── Pull-to-load-older history ────────────────────────── */
.load-older-trigger {
  display: flex;
  justify-content: center;
  padding: 4px 0 14px;
}
.load-older-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--muted);
  border-radius: 100px;
  padding: 6px 14px;
  font-size: .78rem;
  font-family: inherit;
  cursor: pointer;
  transition: background .15s, color .15s;
}
.load-older-btn:hover { background: var(--bg); color: var(--text); }
.load-older-btn:disabled { cursor: default; opacity: .7; }
.load-older-btn .spinner {
  display: inline-block;
  width: 12px; height: 12px;
  border: 2px solid color-mix(in srgb, var(--muted) 35%, transparent);
  border-top-color: var(--muted);
  border-radius: 50%;
  animation: spin .7s linear infinite;
}
body.reduced-motion .load-older-btn .spinner { animation-duration: 1.4s; }

/* ── Sticky date dividers ───────────────────────────────── */
.date-divider {
  position: sticky;
  top: 6px;
  z-index: 15;
  display: flex;
  justify-content: center;
  margin: 14px 0;
  pointer-events: none;
}
.date-divider span {
  background: color-mix(in srgb, var(--surface) 88%, transparent);
  -webkit-backdrop-filter: blur(4px);
  backdrop-filter: blur(4px);
  border: 1px solid var(--border);
  border-radius: 100px;
  padding: 3px 12px;
  font-size: .72rem;
  font-weight: 600;
  color: var(--muted);
  opacity: 0;
  transition: opacity .25s ease;
}
.chat-messages.is-scrolling .date-divider span {
  opacity: 1;
}


/* ── Search bar — above composer (desktop) ───────────────── */
#search-overlay {
  display: none;
  flex-shrink: 0;
  align-items: center;
  gap: 8px;
  padding: 8px 16px;
  background: var(--surface);
  border-top: 1px solid var(--border);
  animation: searchIn .15s ease;
}
#search-overlay.open { display: flex; }
@keyframes searchIn {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: translateY(0); }
}
#search-input {
  flex: 1; font-size: .875rem; padding: 7px 11px;
  border: 1.5px solid var(--primary); border-radius: 8px;
  background: var(--bg); color: var(--text); outline: none;
  min-width: 0;
}
#search-count { font-size: .75rem; color: var(--muted); white-space: nowrap; }
.search-load-more-link { color: var(--primary); cursor: pointer; text-decoration: underline; margin-left: 4px; }
.search-highlight { background: #fef08a; color: #713f12; border-radius: 2px; }
[data-theme="dark"] .search-highlight { background: #854d0e; color: #fef08a; }

/* ── Search bar — mobile: slide down from top ─────────────── */
@media (max-width: 768px) {
  #search-overlay {
    /* override the flex-item layout — become a fixed top panel */
    position: fixed !important;
    top: 52px !important; /* sits flush under the mobile topbar */
    left: 0 !important; right: 0 !important;
    z-index: 120 !important;
    display: flex !important;        /* always in layout so transform works */
    flex-direction: row;
    align-items: center;
    gap: 8px;
    padding: 10px 12px 12px !important;
    background: var(--surface) !important;
    border-top: none !important;
    border-bottom: 1px solid var(--border);
    box-shadow: 0 6px 24px rgba(0,0,0,.13) !important;
    border-radius: 0 0 16px 16px !important;
    /* hidden by default — transform up out of view */
    transform: translateY(-110%);
    opacity: 0;
    pointer-events: none;
    transition: transform .28s cubic-bezier(.16,1,.3,1), opacity .2s ease;
    animation: none !important; /* disable desktop keyframe */
  }
  #search-overlay.open {
    transform: translateY(0) !important;
    opacity: 1 !important;
    pointer-events: auto !important;
  }
  /* Notch-aware: push down by the safe-area top inset if needed */
  @supports (top: env(safe-area-inset-top)) {
    #search-overlay {
      top: calc(52px + env(safe-area-inset-top, 0px)) !important;
    }
  }
}
.search-current { background: #fb923c; color: #fff; border-radius: 2px; }

/* ── NEW: Word count badge ────────────────────────────────── */
.msg-words { font-size: .68rem; color: var(--muted); margin-left: 4px; }
/* Word/token counts eat scarce horizontal space in the narrow mobile
   msg-meta row — desktop keeps them, mobile only shows time + action buttons. */
@media (max-width: 768px) {
  .msg-words, .msg-tokens { display: none; }
}

/* msg-meta action buttons must always be visible, on every screen size —
   never hover-reveal. Several of them (.copy-btn in app.css, .quote-btn/
   .msg-pin-btn/.msg-edit-btn/.msg-branch-btn here) default to
   display:none/opacity:0 and only appear on ".msg:hover"/".msg-user:hover".
   That's unreachable on touch (mobile has no real hover state) and, per
   explicit request, unwanted on desktop too — always-on beats hover-reveal
   everywhere now. !important is required to outrank those hover-pseudo
   rules, which have higher selector specificity than a plain single-class
   override. If the now-always-visible row doesn't fit the available width,
   it becomes a horizontally scrollable strip (flex-wrap:nowrap +
   overflow-x:auto) instead of wrapping to a second line or clipping the
   overflow buttons — harmless on desktop widths where it rarely overflows. */
.msg-meta {
  flex-wrap: nowrap;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.msg-meta::-webkit-scrollbar { display: none; }
.msg-meta > * { flex-shrink: 0; }
.copy-btn, .quote-btn, .msg-pin-btn, .msg-edit-btn, .msg-branch-btn {
  display: inline-flex !important;
}

/* ── Welcome screen ───────────────────────────────────────────── */
.welcome-screen {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 16px;
  max-width: 600px;
  width: 100%;
  margin: auto;
  padding: 40px 20px;
  animation: welcomeIn .4s cubic-bezier(.16,1,.3,1);
}
@keyframes welcomeIn {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: translateY(0); }
}
.welcome-logo {
  width: 64px; height: 64px;
  background: var(--grad-brand); color: var(--on-accent);
  border-radius: 18px;
  display: flex; align-items: center; justify-content: center;
  box-shadow: var(--shadow-accent);
}
.welcome-screen h2 {
  font-size: 1.6rem;
  font-weight: 700;
  color: var(--text);
  margin: 0;
}
.welcome-sub {
  font-size: .88rem;
  color: var(--muted);
  margin: -6px 0 0;
}
.welcome-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  justify-content: center;
  max-width: 560px;
}
.chip {
  padding: 9px 16px;
  border: 1px solid var(--border);
  border-radius: 20px;
  font-size: .82rem;
  font-weight: 500;
  cursor: pointer;
  background: var(--surface);
  color: var(--text);
  transition: all .15s;
  font-family: inherit;
  animation: chipIn .3s cubic-bezier(.16,1,.3,1) both;
}
.chip:hover {
  background: var(--primary-light);
  border-color: var(--primary);
  color: var(--primary);
  transform: translateY(-1px);
}
@keyframes chipIn {
  from { opacity: 0; transform: translateY(8px) scale(.97); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
.chip:nth-child(1){animation-delay:.05s}
.chip:nth-child(2){animation-delay:.1s}
.chip:nth-child(3){animation-delay:.15s}
.chip:nth-child(4){animation-delay:.2s}
.chip:nth-child(5){animation-delay:.25s}
.chip:nth-child(6){animation-delay:.3s}

/* Welcome-screen elements that populate after an async fetch (e.g. the
   Modules row, which waits on api/modules.php) — fade+slide in instead of
   an abrupt display:none -> block pop once their content is ready. The JS
   toggles the .show class after setting display, one requestAnimationFrame
   later, so the transition actually has a starting state to animate from. */
.welcome-fade-in {
  opacity: 0;
  transform: translateY(-6px);
  transition: opacity .35s ease, transform .35s ease;
}
.welcome-fade-in.show {
  opacity: 1;
  transform: translateY(0);
}

.welcome-refresh-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: none;
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 7px 14px;
  font-size: .78rem;
  color: var(--muted);
  cursor: pointer;
  font-family: inherit;
  transition: border-color .15s, color .15s;
}
@keyframes spin { to { transform: rotate(360deg); } }

@keyframes mgmtIn { from { opacity:0; transform:scale(.95) translateY(16px); } to { opacity:1; transform:none; } }

/* ═══════════════════════════════════════════════════════════════
   MOBILE OPTIMIZATIONS — iOS & Android  (≤768px)
   Consolidated, final-word overrides. All safe-area aware.
   ═══════════════════════════════════════════════════════════════ */

/* ── Phase 6: iOS Safari hardening — global baseline ────────────────────── */

/* Kill tap delay + double-tap zoom globally */
html { touch-action: manipulation; }

/* Crisp text on Retina */
body {
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

/* Touch interaction baseline — global, not inside @media */
button, a, [role="button"],
.chip, .session-item, .composer-tool-btn, .send-btn,
.mobile-icon-btn, .mobile-menu-btn, .mobile-new-chat-btn,
.sc-picker-item, .sf-dropdown-item,
.code-copy-btn, .code-save-btn {
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

/* Phase 6: hover-only rules must not stick on touch devices */
@media (hover: hover) and (pointer: fine) {
  .composer-tool-btn:hover      { background: var(--hover-bg, rgba(0,0,0,.06)); }
  .session-item:hover           { background: var(--hover-bg, rgba(0,0,0,.04)); }
  .mobile-icon-btn:hover        { background: var(--border) !important; }
  .mobile-menu-btn:hover        { background: var(--border) !important; }
  .btn:hover                    { filter: brightness(.94); }
  .send-btn:not(:disabled):hover{ filter: brightness(.9); }
  .msg-action-btn:hover         { background: var(--border); }
  .code-copy-btn:hover, .code-save-btn:hover { background: var(--border); opacity: 1; }
}

@media (max-width: 768px) {

  /* --- Viewport & shell --- */
  html, body { height: 100dvh !important; }

  .app-shell {
    height: 100dvh !important;
    /* sidebar is off-canvas (position:fixed), row direction is correct */
  }

  .app-main {
    /* position:fixed;inset:0 is the only iOS-reliable layout for keyboard handling.
       Unlike height:100dvh (which fights flex and lags on older iOS), a fixed
       element's bottom:0 tracks the visual viewport boundary directly —
       it sits above the keyboard when open, returns to screen-bottom when closed.
       Combined with interactive-widget=resizes-content in the meta tag, the
       flex layout reflows automatically with no JS and no gap. */
    position: fixed !important;
    top: calc(52px + env(safe-area-inset-top, 0px)) !important; /* below topbar */
    left: 0 !important;
    right: 0 !important;
    /* --kb-inset is set by JS from visualViewport on iOS (where the meta-tag
       interactive-widget hint is ignored) so the composer rises above the
       on-screen keyboard. It stays 0 on Android/desktop. */
    bottom: var(--kb-inset, 0px) !important;
    height: auto !important;   /* height is defined by top+bottom, not dvh */
    width: 100vw !important;
    padding: 0 !important;     /* no internal offset — top: already places us below topbar */
    display: flex !important;
    flex-direction: column !important;
    overflow: hidden !important;
  }

  /* --- Mobile topbar: account for iPhone notch / Dynamic Island --- */
  .mobile-topbar {
    display: flex !important;
    position: fixed !important;
    top: 0 !important; left: 0 !important; right: 0 !important;
    z-index: 99 !important;
    /* Grow taller on notched iPhones to sit below the status bar */
    padding-top: max(10px, env(safe-area-inset-top)) !important;
    padding-bottom: 8px !important;
    padding-left: 10px !important;
    padding-right: 10px !important;
    min-height: calc(52px + env(safe-area-inset-top, 0px)) !important;
    /* Matches <meta name="theme-color"> (ui_theme_color()) so the browser's
       address-bar area and this bar read as one continuous surface. */
    background: var(--topbar-bg) !important;
    /* backdrop-filter intentionally omitted — combined with the transform-based
       hide/show animation below, it leaves a "stuck" blurred layer on mobile
       Chrome/Safari that doesn't clear when the topbar slides away */
    box-shadow: 0 1px 0 var(--border) !important;
    /* Phase 3: scroll-hide transition */
    transition: transform .25s cubic-bezier(.4,0,.2,1), box-shadow .25s !important;
    will-change: transform !important;
  }

  /* Phase 3: topbar hidden (scrolling down) */
  .mobile-topbar.topbar-hidden {
    transform: translateY(-110%) !important;
    box-shadow: none !important;
  }

  /* Phase 3: when topbar is hidden, expand app-main to fill from safe-area top */
  .app-main.topbar-hidden-mode {
    top: env(safe-area-inset-top, 0px) !important;
  }

  /* ── Guest mode: no title/actions left in the topbar (see dashboard.php),
     so the bar itself goes invisible and the menu button floats free on top
     of the content instead of sitting inside an otherwise-empty strip. The
     guest welcome screen then starts from the true top of the viewport. */
  .mobile-topbar.mobile-topbar-guest {
    background: none !important;
    box-shadow: none !important;
    border: none !important;
    padding: 0 !important;
    min-height: 0 !important;
    pointer-events: none !important;
  }
  .mobile-topbar.mobile-topbar-guest .mobile-menu-btn {
    pointer-events: auto !important;
    position: fixed !important;
    top: max(14px, env(safe-area-inset-top, 14px)) !important;
    left: max(12px, env(safe-area-inset-left, 12px)) !important;
    z-index: 101 !important;
    width: 40px !important;
    height: 40px !important;
    border-radius: 10px !important;
    background: var(--surface) !important;
    box-shadow: 0 2px 12px rgba(0,0,0,.18) !important;
    display: flex !important;
    align-items: center !important;
    justify-content: center !important;
  }
  .app-main.guest-mode {
    top: 0 !important;
  }

  /* --- Sidebar: full-height off-canvas drawer --- */
  .app-sidebar {
    position: fixed !important;
    left: 0 !important;
    top: 0 !important;
    height: 100dvh !important;
    width: 82vw !important;
    max-width: 320px !important;
    z-index: 100 !important;
    transform: translateX(-100%) !important;
    transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1) !important;
    box-shadow: none !important;
    /* Sidebar is a fixed flex column — session-list scrolls, NOT the sidebar */
    display: flex !important;
    flex-direction: column !important;
    overflow: hidden !important;
    overscroll-behavior: contain !important;
    /* GPU-accelerate the slide animation — prevents jank on Safari */
    will-change: transform;
    -webkit-backface-visibility: hidden;
    backface-visibility: hidden;
    /* Always opaque — prevents transparent gap during slide-in animation */
    background: var(--surface) !important;
    /* Notch / Dynamic Island: push content below status bar */
    padding-top: max(0px, env(safe-area-inset-top)) !important;
    /* Home indicator: keep bottom items above the swipe bar */
    padding-bottom: max(0px, env(safe-area-inset-bottom)) !important;
  }

  .app-sidebar.open {
    transform: translateX(0) !important;
    box-shadow: 8px 0 40px rgba(0,0,0,.28) !important;
  }

  /* While a finger is dragging the drawer, kill the transition so the panel and
     backdrop track the finger 1:1 instead of easing ~300 ms behind it. The JS
     removes .dragging on release so the snap-to-open/closed still animates. */
  .app-sidebar.dragging,
  .sidebar-backdrop.dragging {
    transition: none !important;
  }

  /* Only the session list scrolls; header/search/footer stay fixed */
  #session-list {
    flex: 1 1 0 !important;
    min-height: 0 !important;
    /* See app.css's .session-list for why height:0 is load-bearing here —
       it makes the J1 virtual-scroller's huge padding-bottom physically
       incapable of becoming real box height. */
    height: 0 !important;
    overflow-y: auto !important;
    -webkit-overflow-scrolling: touch !important;
    overscroll-behavior-y: contain !important;
    /* See app.css's #session-list — the J1 virtual-scroll module rewrites
       this element's own padding on scroll, which fights CSS Scroll
       Anchoring and can feedback-loop into a runaway padding-top ("expands
       over everything"). Opt out of anchoring here too (desktop already had
       it) — mobile touch/momentum scrolling makes the feedback loop even
       easier to trigger. */
    overflow-anchor: none !important;
  }

  /* Collapse button is meaningless on mobile — sidebar is always off-canvas */
  #sidebar-collapse-btn { display: none !important; }

  /* --- Chat messages area --- */
  .chat-messages {
    flex: 1 1 0 !important;
    min-height: 0 !important;
    overflow-y: auto !important;
    overflow-x: hidden !important;
    -webkit-overflow-scrolling: touch !important;
    overscroll-behavior-y: contain !important;
    padding: 12px 10px 8px !important;
  }

  /* Generated-file card: keep actions on the header row next to the filename —
     shrink to icon-only buttons instead of wrapping to a full-width row. The
     icons are drawn at a fixed 12px in the markup (sized for sitting next to
     text); at icon-only size that reads as an near-invisible speck, so bump
     both the button and the icon itself up on mobile. */
  .gfc-btn { width: 40px; height: 40px; padding: 0; justify-content: center; gap: 0; color: var(--text); }
  .gfc-btn svg { width: 20px; height: 20px; }
  .gfc-btn-label { display: none; }

  /* File preview modal: the toolbar row has too many buttons to fit on a
     narrow screen and used to overflow past the box's clipped edge, hiding
     whatever came last (Close). Make the row scrollable so nothing is lost,
     and pin Close to the box corner so it's reachable without scrolling.
     Desktop is untouched — it never had this problem. */
  #fp-header { padding-right: 46px; }
  #fp-header-tools {
    overflow-x: auto; -webkit-overflow-scrolling: touch; min-width: 0;
    scrollbar-width: none;
  }
  #fp-header-tools::-webkit-scrollbar { display: none; }
  #fp-close-btn {
    position: absolute; top: 8px; right: 8px; z-index: 2;
    background: var(--surface); box-shadow: 0 1px 5px rgba(0,0,0,.15);
  }
  #fp-close-sep { display: none; }

  /* --- Composer — in-flow flex child, rides above keyboard via flex+dvh --- */
  .chat-input-wrap {
    flex-shrink: 0 !important;
    position: relative !important;
    z-index: 10 !important;
    background: var(--surface) !important;
    border-top: 1px solid var(--border) !important;
    /* Safe-area padding pushes content above home indicator.
       When keyboard is open iOS 15.4+ sets env(safe-area-inset-bottom)=0
       automatically — no JS needed, no gap, no jump. */
    padding: 8px 10px max(10px, env(safe-area-inset-bottom, 8px)) !important;
  }

  .composer-card {
    border-radius: 14px !important;
  }

  /* Prevent iOS auto-zoom when tapping input (requires font-size ≥ 16px) */
  #chat-input {
    font-size: 16px !important;
    min-height: 44px !important;
    max-height: 120px !important;
  }

  /* Toolbar: single scrollable row, nothing hidden */
  .composer-toolbar {
    padding: 4px 6px 6px !important;
    overflow: hidden !important;
    min-height: 42px !important;
  }

  .composer-tools-left {
    overflow-x: auto !important;
    overflow-y: hidden !important;
    scrollbar-width: none !important;
    -webkit-overflow-scrolling: touch !important;
    flex-wrap: nowrap !important;
    gap: 1px !important;
  }
  .composer-tools-left::-webkit-scrollbar { display: none !important; }

  /* 44px minimum touch targets throughout toolbar */
  .composer-tool-btn {
    min-height: 36px !important;
    padding: 6px 10px !important;
    flex-shrink: 0 !important;
  }

  .composer-model-pill {
    flex-shrink: 0 !important;
    min-height: 36px !important;
    padding: 4px 8px !important;
  }

  .composer-model-select { max-width: 110px !important; font-size: .75rem !important; }

  .composer-temp-pill {
    min-height: 36px !important;
    padding: 4px 8px !important;
    flex-shrink: 0 !important;
  }
  .composer-temp-pill input[type=range] {
    width: 48px !important;
    /* taller touch area */
    height: 20px !important;
    cursor: pointer;
  }

  .send-btn {
    width: 40px !important;
    height: 40px !important;
    border-radius: 11px !important;
    flex-shrink: 0 !important;
  }

  .char-counter { display: none !important; }

  /* --- Messages: user bubbles stay a capped chat bubble; AI responses go
     full width for easier reading on a small screen. (This used to cap
     .msg — including AI messages — at 94%, leaving a visible gap on the
     right; that's what the "padding on the right side" report was.) --- */
  .msg-user { max-width: 94% !important; margin-left: auto !important; }
  .msg-ai   { max-width: 100% !important; width: 100% !important; }
  .msg-ai .msg-avatar { display: none !important; } /* reclaim the avatar's width for text */
  .msg-ai .msg-body { max-width: 100% !important; width: 100% !important; }
  .msg-content, .msg-bubble { font-size: .9rem !important; }
  .msg-bubble { padding: 10px 12px !important; }

  /* Re-assert the "clean card" bubble look from the desktop rule further
     down this file (.msg-ai/.msg-user .msg-bubble, ~line 7140) — an older,
     superseded mobile rule in app.css (@media max-width:768px, loaded
     before this file) forces a flat, uniform border-radius:10px !important
     on .msg-ai .msg-bubble, which wins the radius property over dashboard.css's
     un-media-queried rule (equal specificity, but app.css's is !important and
     this file's plain rule isn't). That's the only thing that made mobile
     bubbles look different from desktop — background/border/shadow already
     carried over fine. Repeating the desktop values here, also !important,
     wins on source order (this file loads after app.css) and restores the
     same tucked-corner card on mobile. */
  .msg-ai .msg-bubble {
    background: var(--surface-2) !important;
    border-radius: var(--r-lg, 20px) !important;
    border-top-left-radius: var(--r-xs, 6px) !important;
    box-shadow: var(--shadow-1) !important;
  }
  .msg-user .msg-bubble {
    border-radius: var(--r-lg, 20px) !important;
    border-top-right-radius: var(--r-xs, 6px) !important;
    box-shadow: var(--shadow-1) !important;
  }

  /* --- Skeleton loading rows (_skeletonMessagesHTML() in dashboard.js) must
     mirror whatever the real bubbles do on this breakpoint, or the preloader
     visibly swaps its own look the instant real content lands. The AI-side
     skeleton row (plain .skeleton-msg, no .user) still showed its avatar and
     an inset bubble here even though .msg-ai .msg-avatar is hidden and
     .msg-ai goes full width above — that mismatch is what "skeleton css for
     mobile" was reporting. */
  .skeleton-msg:not(.user) .msg-avatar { display: none !important; }
  .skeleton-msg:not(.user) .msg-bubble { width: 100% !important; }
  .skeleton-msg .msg-bubble {
    border-radius: var(--r-lg, 20px) !important;
    border-top-left-radius: var(--r-xs, 6px) !important;
  }
  .skeleton-msg.user .msg-bubble {
    border-top-left-radius: var(--r-lg, 20px) !important;
    border-top-right-radius: var(--r-xs, 6px) !important;
  }

  /* --- Code blocks: scroll horizontally, don't overflow --- */
  .code-block-wrap {
    max-width: 100% !important;
    overflow: hidden !important;
  }
  .code-block-wrap pre {
    overflow-x: auto !important;
    -webkit-overflow-scrolling: touch !important;
  }
  .code-block-wrap pre code {
    font-size: .76rem !important;
    white-space: pre-wrap !important;
    word-break: break-all !important;
    overflow-wrap: break-word !important;
  }
  pre { font-size: .76rem !important; overflow-x: auto !important; }
  code { font-size: .78rem !important; }

  /* --- Session items: always show ⋯ button on touch --- */
  .session-more-btn { opacity: 1 !important; width: 36px !important; height: 36px !important; min-width: 36px !important; }
  .session-item { min-height: 44px !important; }


  /* --- Modals: slide up from bottom on mobile --- */
  .modal-overlay {
    padding: 12px !important;
    align-items: flex-end !important;
  }
  .modal-card {
    border-radius: 18px 18px 14px 14px !important;
    padding: 20px 16px max(20px, env(safe-area-inset-bottom)) !important;
  }

/* --- Slash command / shortcut picker: full width --- */
  .slash-menu { left: 0 !important; right: 0 !important; width: auto !important; }
  .sc-picker  { left: 8px !important; right: 8px !important; }

  /* --- Welcome screen --- */
  .welcome-screen { padding: 20px 14px 16px !important; gap: 8px !important; }
  .welcome-screen h2 { font-size: 1.2rem !important; }
  .welcome-chips { gap: 6px !important; }
  .chip { padding: 7px 12px !important; font-size: .8rem !important; }

  /* --- Hide hints that only make sense on desktop --- */
  .chat-hint { display: none !important; }
  .btn-label-hide-mobile { display: none !important; }

  /* --- Mobile session title truncation --- */
  #mobile-session-title {
    max-width: 150px !important;
    overflow: hidden !important;
    text-overflow: ellipsis !important;
    white-space: nowrap !important;
    font-size: .88rem !important;
  }

  /* --- Floating show-sidebar button: hidden on mobile (topbar handles it) --- */
  #sidebar-show-btn,
  .sidebar-show-btn { display: none !important; }

  /* --- Sidebar-collapsed class must not affect mobile off-canvas sidebar --- */
  .app-shell.sidebar-collapsed .app-sidebar {
    width: 82vw !important;
    max-width: 320px !important;
    min-width: unset !important;
    /* transform is what controls visibility on mobile, not width */
  }
}

/* ── Landscape notch/cutout safe areas (mobile) ───────────────────
   In landscape, the notch/home-indicator sit on the LEFT or RIGHT
   edge rather than top/bottom. Pad the fixed UI so controls and text
   aren't obscured by the cutout or rounded corners. */
@media (max-width: 900px) and (orientation: landscape) {
  .mobile-topbar {
    padding-left: max(10px, env(safe-area-inset-left)) !important;
    padding-right: max(10px, env(safe-area-inset-right)) !important;
  }
  .chat-messages {
    padding-left: max(12px, env(safe-area-inset-left)) !important;
    padding-right: max(12px, env(safe-area-inset-right)) !important;
  }
  .chat-input-wrap {
    padding-left: max(8px, env(safe-area-inset-left)) !important;
    padding-right: max(8px, env(safe-area-inset-right)) !important;
  }
  .app-sidebar {
    padding-left: env(safe-area-inset-left) !important;
  }
  #mobile-tool-sheet {
    padding-left: env(safe-area-inset-left) !important;
    padding-right: env(safe-area-inset-right) !important;
  }
  #composer-show-fab {
    right: max(16px, calc(env(safe-area-inset-right) + 8px)) !important;
  }
}

/* Extra-small screens: iPhone SE / compact Android (≤380px) */
@media (max-width: 380px) {
  .composer-model-select { max-width: 80px !important; }
  .composer-temp-pill    { display: none !important; }
  .welcome-screen h2     { font-size: 1.1rem !important; }
  .chip                  { font-size: .76rem !important; padding: 6px 10px !important; }
  #mobile-session-title  { max-width: 110px !important; }
}

/* ═══════════════════════════════════════════════════════════════
   MODEL PILL — proper shading so the active model is always clear
   (fixes the orphaned rule earlier in the file)
   ═══════════════════════════════════════════════════════════════ */
.composer-model-pill {
  background: color-mix(in srgb, var(--primary) 10%, transparent);
  border: 1px solid color-mix(in srgb, var(--primary) 22%, transparent);
  border-radius: 8px;
  padding: 5px 10px;
  gap: 6px;
  transition: background .15s, border-color .15s;
}
.composer-model-pill:hover {
  background: color-mix(in srgb, var(--primary) 17%, transparent);
  border-color: color-mix(in srgb, var(--primary) 34%, transparent);
}
.composer-model-pill svg { color: var(--primary); }
.composer-model-select {
  color: var(--primary);
  font-weight: 700;
  font-size: .8rem;
}

/* ═══════════════════════════════════════════════════════════════
   COMPOSER CARD — base polish (surface bg, subtle shadow)
   ═══════════════════════════════════════════════════════════════ */
.composer-card {
  background: var(--surface);
  box-shadow: 0 2px 12px rgba(0,0,0,.07), 0 1px 2px rgba(0,0,0,.04);
}
[data-theme="dark"] .composer-card {
  box-shadow: 0 2px 12px rgba(0,0,0,.35), 0 1px 2px rgba(0,0,0,.2);
}

/* ═══════════════════════════════════════════════════════════════
   COMPOSER MOBILE HEADER — hidden on desktop, shown on mobile
   ═══════════════════════════════════════════════════════════════ */
.composer-mobile-header { display: none; }

/* ═══════════════════════════════════════════════════════════════
   MOBILE TOPBAR & COMPOSER HEADER — visual redesign (≤768px)
   ═══════════════════════════════════════════════════════════════ */
@media (max-width: 768px) {

  /* --- Topbar layout --- */
  .mobile-topbar { gap: 8px !important; align-items: center !important; }

  /* Hamburger: clean rounded square, matches icon buttons */
  .mobile-menu-btn {
    width: 38px !important;
    height: 38px !important;
    border-radius: 10px !important;
    background: var(--bg) !important;
    border: 1px solid var(--border) !important;
    flex-shrink: 0 !important;
    color: var(--text) !important;
    display: flex !important;
    align-items: center !important;
    justify-content: center !important;
    transition: background .15s !important;
  }
  .mobile-menu-btn:active { background: var(--border) !important; }

  /* Title: fills remaining space, truncates */
  .mobile-topbar-title {
    flex: 1 !important;
    min-width: 0 !important;
    gap: 7px !important;
    font-size: .92rem !important;
    font-weight: 700 !important;
    color: var(--text) !important;
    overflow: hidden !important;
  }

  /* Actions row */
  .mobile-topbar-actions {
    display: flex !important;
    align-items: center !important;
    gap: 6px !important;
    flex-shrink: 0 !important;
  }

  /* All icon buttons: consistent outline style */
  .mobile-icon-btn {
    width: 36px !important;
    height: 36px !important;
    border-radius: 10px !important;
    background: var(--bg) !important;
    border: 1px solid var(--border) !important;
    color: var(--text) !important;
    display: flex !important;
    align-items: center !important;
    justify-content: center !important;
    flex-shrink: 0 !important;
    transition: background .15s, box-shadow .15s !important;
  }
  .mobile-icon-btn:active { background: var(--border) !important; }

  /* New-chat button: solid primary, clearly the primary action */
  #mobile-new-chat-btn {
    background: var(--primary) !important;
    color: #fff !important;
    border-color: transparent !important;
    box-shadow: 0 2px 8px color-mix(in srgb, var(--primary) 40%, transparent) !important;
  }
  #mobile-new-chat-btn:active {
    background: var(--primary-hover, #1d4ed8) !important;
    box-shadow: none !important;
  }

  /* Mobile search dropdown */
  #mobile-search-menu {
    display: none; position: fixed; z-index: 200;
    background: var(--surface); border: 1px solid var(--border);
    border-radius: 12px; box-shadow: 0 8px 28px rgba(0,0,0,.18);
    min-width: 180px; overflow: hidden;
  }
  #mobile-search-menu.open { display: block; }
  .msm-item {
    display: flex; align-items: center; gap: 10px;
    padding: 11px 14px; font-size: .84rem; color: var(--text);
    background: none; border: none; width: 100%; text-align: left;
    cursor: pointer; font-family: inherit; transition: background .12s;
  }
  .msm-item:hover { background: var(--bg); }
  .msm-item svg { flex-shrink: 0; color: var(--muted); }
  .msm-item + .msm-item { border-top: 1px solid var(--border); }

  /* --- Composer mobile header --- */
  .composer-mobile-header {
    display: flex !important;
    align-items: center !important;
    justify-content: space-between !important;
    padding: 8px 12px 6px !important;
    border-bottom: 1px solid var(--border) !important;
  }

  .composer-mobile-label {
    display: flex;
    align-items: center;
    gap: 5px;
    font-size: .68rem;
    font-weight: 700;
    color: var(--muted);
    text-transform: uppercase;
    letter-spacing: .07em;
  }
  .composer-mobile-label svg { flex-shrink: 0; color: var(--primary); }

  .composer-hide-btn {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 4px 11px;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 8px;
    font-size: .72rem;
    font-weight: 600;
    color: var(--muted);
    cursor: pointer;
    font-family: inherit;
    transition: background .15s, color .15s, border-color .15s;
    -webkit-tap-highlight-color: transparent;
    touch-action: manipulation;
  }
  .composer-hide-btn:hover,
  .composer-hide-btn:active {
    background: var(--border);
    color: var(--text);
    border-color: var(--border);
  }

  /* Textarea loses top padding when header is present */
  #chat-input { padding-top: 10px !important; }

  /* Model pill: slightly larger shading on mobile */
  .composer-model-pill {
    background: color-mix(in srgb, var(--primary) 12%, transparent) !important;
    border-color: color-mix(in srgb, var(--primary) 26%, transparent) !important;
  }
  .composer-model-select {
    color: var(--primary) !important;
    font-weight: 700 !important;
  }
}

/* ═══════════════════════════════════════════════════════════════
   MODEL LABEL — truncated display span + invisible select overlay
   ═══════════════════════════════════════════════════════════════ */
.composer-model-pill {
  position: relative;
}

/* Visible truncated label */
.composer-model-label {
  max-width: 130px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: .8rem;
  font-weight: 700;
  color: var(--primary);
  pointer-events: none;
  display: block;
  line-height: 1;
}

/* The native <select> is kept only as a value/state holder for the
   searchable model-picker dialog (#model-picker-overlay) — fully hidden
   and non-interactive so it doesn't intercept clicks meant for the
   .model-picker-trigger button. */
.composer-model-select {
  position: absolute !important;
  width: 0 !important;
  height: 0 !important;
  opacity: 0 !important;
  pointer-events: none !important;
  max-width: unset !important;
}

/* Visible trigger button replacing the old select-overlay */
.model-picker-trigger {
  display: inline-flex; align-items: center; gap: 5px;
  background: none; border: none; cursor: pointer;
  color: inherit; font: inherit; padding: 0;
}

@media (max-width: 768px) {
  .composer-model-label { max-width: 90px; }
  .composer-search-btn { display: none !important; }
}
@media (max-width: 380px) {
  .composer-model-label { max-width: 70px; }
}

/* ═══════════════════════════════════════════════════════════════
   COMPOSER TOOLBAR — redesign
   ═══════════════════════════════════════════════════════════════ */

/* Toolbar row */
.composer-toolbar {
  display: flex !important;
  align-items: center !important;
  justify-content: space-between !important;
  gap: 8px !important;
  padding: 7px 10px 9px !important;
  border-top: 1px solid var(--border) !important;
  background: color-mix(in srgb, var(--bg) 55%, var(--surface)) !important;
  min-height: 46px !important;
  border-radius: 0 0 14px 14px !important;
}

/* Left flex row */
.composer-tools-left {
  display: flex !important;
  align-items: center !important;
  gap: 7px !important;
  flex: 1 !important;
  min-width: 0 !important;
  overflow: hidden !important;
  flex-wrap: nowrap !important;
}

/* Tool group — desktop: transparent, each button is standalone */
.composer-tool-group {
  display: inline-flex;
  align-items: center;
  background: none;
  border: none;
  border-radius: 0;
  padding: 0;
  gap: 3px;
  flex-shrink: 1;
  min-width: 0;
  overflow: hidden;
}

/* Separators hidden on desktop */
.tool-sep { display: none; }

/* Each button gets its own border on desktop */
.composer-tool-group .composer-tool-btn {
  background: var(--surface) !important;
  border: 1px solid var(--border) !important;
  border-radius: 9px !important;
}
.composer-tool-group .composer-tool-btn:hover {
  background: color-mix(in srgb, var(--primary) 10%, transparent) !important;
  border-color: color-mix(in srgb, var(--primary) 30%, transparent) !important;
  color: var(--primary) !important;
}

/* Mobile: grouped pill style */
@media (max-width: 768px) {
  .composer-tool-group {
    background: var(--surface) !important;
    border: 1px solid var(--border) !important;
    border-radius: 10px !important;
    padding: 2px 3px !important;
    gap: 1px !important;
    overflow-x: auto !important;
    scrollbar-width: none !important;
  }
  .composer-tool-group::-webkit-scrollbar { display: none !important; }
  .tool-sep {
    display: inline-block !important;
    width: 1px !important;
    height: 14px !important;
    background: var(--border) !important;
    flex-shrink: 0 !important;
    border-radius: 1px !important;
    margin: 0 1px !important;
  }
  .composer-tool-group .composer-tool-btn {
    background: none !important;
    border: none !important;
    border-radius: 8px !important;
  }
  .composer-tool-group .composer-tool-btn:hover {
    background: color-mix(in srgb, var(--primary) 10%, transparent) !important;
    border-color: transparent !important;
  }
}

/* Individual tool button */
.composer-tool-btn {
  display: inline-flex !important;
  align-items: center !important;
  gap: 5px !important;
  padding: 5px 9px !important;
  background: none !important;
  border: none !important;
  cursor: pointer !important;
  border-radius: 8px !important;
  color: var(--muted) !important;
  font-size: .72rem !important;
  font-family: inherit !important;
  font-weight: 600 !important;
  letter-spacing: .01em !important;
  transition: background .15s, color .15s !important;
  white-space: nowrap !important;
  flex-shrink: 0 !important;
}
.composer-tool-btn svg {
  flex-shrink: 0 !important;
  transition: color .15s;
}
/* Capability-gated hide: the display:inline-flex !important above beats
   inline style="display:none", so JS hides these buttons via this class. */
.composer-tool-btn.tool-btn-hidden,
.tool-sep.tool-btn-hidden { display: none !important; }
.composer-tool-btn:hover {
  background: color-mix(in srgb, var(--primary) 10%, transparent) !important;
  color: var(--primary) !important;
}
.composer-tool-btn:hover svg { color: var(--primary); }
.composer-tool-btn.active {
  background: color-mix(in srgb, var(--primary) 14%, transparent) !important;
  color: var(--primary) !important;
}

/* Generation lock — while an image/video job is in flight, disable the rest
   of the composer (text input, model picker, mode buttons, draw/video option
   bars, attach) so the user can't start an overlapping generation or switch
   modes mid-request. The send/cancel button stays interactive (image
   generation can be cancelled mid-flight via it). */
.composer-card.gen-locked #chat-input,
.composer-card.gen-locked #composer-tool-group,
.composer-card.gen-locked .draw-mode-bar,
.composer-card.gen-locked .composer-model-pill {
  pointer-events: none !important;
  opacity: .55 !important;
}
.composer-card.gen-locked #send-btn,
.composer-card.gen-locked #send-btn * {
  pointer-events: auto !important;
  opacity: 1 !important;
}
/* ...unless it's actually disabled (video generation has no cancel action —
   see _applyComposerLockState), in which case it should look and behave
   disabled like the rest of the locked composer. */
.composer-card.gen-locked #send-btn:disabled,
.composer-card.gen-locked #send-btn:disabled * {
  pointer-events: none !important;
  opacity: .55 !important;
}

/* Red "stop" tint while an image/audio generation is in flight — mirrors
   #chat-input-row.streaming's red send-btn in text mode (see stopBtnPulse
   above), and hovering swaps the spinner for a stop icon (injected by
   submitInlineImageGen/submitInlineAudioGen alongside the spinner) so the
   button telegraphs what a click does, same as text mode.
   Scoped to :not(:disabled) deliberately — video generation has no cancel
   action (see _applyComposerLockState's comment) and its button stays
   disabled the whole time it's locked, so it must NOT turn red: red here
   means "click to stop", and a red button that does nothing on click reads
   as broken, not as "please wait". Video keeps its normal dimmed-disabled
   look instead — see the plain #send-btn:disabled rule above. */
.composer-card.gen-locked #send-btn:not(:disabled) {
  background: var(--danger, #ef4444) !important;
  box-shadow: 0 2px 10px color-mix(in srgb, var(--danger, #ef4444) 45%, transparent) !important;
  animation: stopBtnPulse 2s ease-in-out infinite;
}
.composer-card.gen-locked #send-btn:not(:disabled):hover {
  filter: brightness(.92);
}
.composer-card.gen-locked #send-btn .gen-stop-icon { display: none; }
.composer-card.gen-locked #send-btn:not(:disabled):hover .img-gen-spinner { display: none; }
.composer-card.gen-locked #send-btn:not(:disabled):hover .gen-stop-icon { display: inline-flex; }

/* Mic sits between the pause and send buttons — pin it to the send button's
   height (34px) and box-size it so its hover highlight lines up with its
   neighbours instead of being a touch shorter. (Hidden on mobile.) */
#mic-btn {
  height: 34px !important;
  box-sizing: border-box !important;
  justify-content: center !important;
}

/* Active modifier buttons get a tinted border on desktop */
.composer-tool-group .composer-tool-btn.active {
  border-color: color-mix(in srgb, var(--primary) 45%, transparent) !important;
}

/* ── Tool expander ────────────────────────────────────────────────── */

/* Floating popup — positioned above the More button via JS */
.tool-group-extra {
  display: none;
  position: fixed;       /* JS sets top/left/right at open time */
  z-index: 400;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 6px 8px;
  box-shadow: 0 -2px 24px rgba(0,0,0,.12), 0 4px 12px rgba(0,0,0,.06);
  flex-wrap: wrap;       /* wrap if too wide for viewport */
  align-items: center;
  gap: 4px;
  white-space: nowrap;
  max-width: calc(100vw - 16px); /* never overflow viewport */
}
.tool-group-extra.open {
  display: flex;
  justify-content: center;
  animation: toolPopIn .15s cubic-bezier(.22,1,.36,1);
}
@keyframes toolPopIn {
  from { opacity: 0; transform: translateY(6px) scale(.97); }
  to   { opacity: 1; transform: translateY(0)   scale(1);   }
}
/* Separators have no meaning in the wrapped popup grid */
.tool-group-extra .tool-sep { display: none !important; }
/* Each button in popup gets its own full border */
.tool-group-extra .composer-tool-btn {
  background: var(--surface) !important;
  border: 1px solid var(--border) !important;
  border-radius: 9px !important;
  flex-shrink: 0;
}
.tool-group-extra .composer-tool-btn:hover {
  background: color-mix(in srgb, var(--primary) 10%, transparent) !important;
  border-color: color-mix(in srgb, var(--primary) 30%, transparent) !important;
  color: var(--primary) !important;
}
.tool-group-extra .composer-tool-btn.active {
  border-color: color-mix(in srgb, var(--primary) 45%, transparent) !important;
}
/* Always show labels inside the popup regardless of screen width */
.tool-group-extra .tool-label { display: inline !important; }

/* Chevron points up when popup is open */
.expand-chevron {
  transition: transform .2s ease;
}
.composer-tool-group.expanded .expand-chevron {
  transform: rotate(-90deg);
}

/* Active-modifier dot on the expand button when collapsed */
.tool-expand-btn { position: relative; }
.tool-expand-btn.has-active::after {
  content: '';
  position: absolute;
  top: 3px; right: 3px;
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--primary);
  border: 1.5px solid var(--surface);
  pointer-events: none;
}

/* Mobile: keep extra tools behind the "More" popup (same as desktop) to avoid
   an overcrowded, endlessly-scrolling toolbar. The popup itself gets a few
   touch-friendly tweaks below. */
@media (max-width: 768px) {
  .tool-group-extra.open {
    /* Anchor as a bottom sheet-style popup, full width, easy to tap */
    left: 8px !important;
    right: 8px !important;
    max-width: calc(100vw - 16px) !important;
    justify-content: flex-start !important;
    gap: 6px !important;
    padding: 8px !important;
  }
  .tool-group-extra .composer-tool-btn {
    padding: 8px 10px !important;
    min-height: 36px !important;
  }
}

/* Tool label — hide on narrow screens */
.tool-label {
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .01em;
}
@media (max-width: 860px) { .tool-label { display: none; } }

/* Model selector — styled as a clear button that opens the picker popup */
.composer-model-pill {
  background: color-mix(in srgb, var(--primary) 10%, transparent) !important;
  border: 1px solid color-mix(in srgb, var(--primary) 24%, transparent) !important;
  border-radius: 10px !important;
  padding: 0 !important;
  gap: 0 !important;
  flex-shrink: 0 !important;
  max-width: none !important;
  width: auto !important;
  transition: background .15s, border-color .15s !important;
}
.composer-model-pill .model-picker-trigger {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 40px;
  padding: 0 12px;
  background: none;
  border: none;
  cursor: pointer;
  border-radius: 10px;
}
.composer-model-pill:hover {
  background: color-mix(in srgb, var(--primary) 16%, transparent) !important;
  border-color: color-mix(in srgb, var(--primary) 40%, transparent) !important;
}
.composer-model-pill .model-picker-trigger > svg:first-child { color: var(--primary); }
.composer-model-label {
  max-width: 140px !important;   /* cap the selected model name in the pill; full name still shows in the picker */
  font-size: .8rem !important;
  font-weight: 700 !important;
  color: var(--primary) !important;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Send button — right side */
.composer-tools-right {
  flex-shrink: 0 !important;
  margin-left: 2px !important;
}
.send-btn {
  width: 34px !important;
  height: 34px !important;
  border-radius: 10px !important;
  box-shadow: 0 2px 8px color-mix(in srgb, var(--primary) 35%, transparent) !important;
  transition: background .15s, transform .1s, box-shadow .15s !important;
}
.send-btn:not(:disabled):hover {
  transform: translateY(-1px) !important;
  box-shadow: 0 4px 14px color-mix(in srgb, var(--primary) 50%, transparent) !important;
}

/* Popover section labels + temperature row — hidden by default,
   revealed only inside the desktop Tools popover below. */
.tgx-label, .tgx-temp { display: none; }

/* ═══════════════════════════════════════════════════════════════
   DESKTOP SMART-COMPOSE REDESIGN  (≥769px)
   Icon-only mode buttons · grouped Tools popover · larger Send
   ═══════════════════════════════════════════════════════════════ */
@media (min-width: 769px) {
  /* Icon-only mode buttons — Tools included, no text label on desktop */
  .composer-tool-group { gap: 4px !important; }
  .composer-tool-group > .composer-tool-btn .tool-label { display: none; }
  .composer-tool-group > .composer-tool-btn {
    padding: 0 !important;
    width: 40px; height: 40px;
    justify-content: center;
    border-radius: 10px;
  }
  .composer-tool-group > .composer-tool-btn svg { width: 18px; height: 18px; }

  /* Tools button — icon-only, same square sizing as the other mode buttons.
     The chevron only made sense next to the "Tools" text label (indicating a
     dropdown); alone in a 40×40 icon square it just looked like a second,
     mismatched icon crowding the sliders glyph, so it's hidden here too. */
  .tool-expand-btn { color: var(--muted); gap: 0 !important; }
  .tool-expand-btn svg:first-of-type { width: 18px; height: 18px; }
  .tool-expand-btn .expand-chevron { display: none; }

  /* Draw bar buttons — same height/radius/sizing as smartcompose card buttons.
     .draw-size-pill/.draw-count-pill (image size, image count, audio voice,
     audio format, video duration/resolution/aspect) must match .draw-model-pill
     and .draw-exit-btn's height here — they were missing from this rule, so
     those pills sat shorter than the Model pill and Exit button beside them. */
  .draw-model-pill,.draw-size-pill,.draw-count-pill { height: 40px; padding: 0 12px !important; border-radius: 10px !important; }
  .draw-model-pill svg,.draw-size-pill svg,.draw-count-pill svg { width: 16px; height: 16px; }
  /* Reference: icon-only square (matches the icon-only mode buttons) */
  .draw-ref-btn { width: 40px; height: 40px; padding: 0 !important; justify-content: center; border-radius: 10px !important; }
  .draw-ref-btn svg { width: 18px; height: 18px; }
  /* Labeled buttons: same height as Tools button */
  .draw-more-btn,.draw-extra-toggle,.draw-exit-btn {
    height: 40px; padding: 0 12px !important; border-radius: 10px !important;
  }
  .draw-more-btn svg,.draw-extra-toggle svg,.draw-exit-btn svg {
    width: 16px; height: 16px;
  }

  /* Bigger mic icon */
  #mic-btn { padding: 0 12px !important; }
  #mic-btn svg { width: 18px; height: 18px; }

  /* Larger, clearly-primary Send button — wider for a nicer proportion */
  .send-btn { width: 56px !important; height: 44px !important; border-radius: 12px !important; }
  .send-btn svg { width: 19px; height: 19px; }

  /* Tools popover → vertical, sectioned panel */
  .tool-group-extra.open {
    flex-direction: column;
    align-items: stretch;
    justify-content: flex-start;
    width: 268px;
    box-sizing: border-box;
    gap: 1px;
    padding: 8px;
    white-space: normal;
  }
  .tool-group-extra .composer-tool-btn {
    width: 100% !important;
    justify-content: flex-start !important;
    gap: 10px !important;
    border: none !important;
    background: transparent !important;
    border-radius: 8px !important;
    padding: 8px 10px !important;
  }
  .tool-group-extra .composer-tool-btn:hover {
    background: color-mix(in srgb, var(--primary) 10%, transparent) !important;
    border: none !important;
  }
  .tool-group-extra .composer-tool-btn .tool-label { display: inline !important; }
  .tool-group-extra .export-wrap { width: 100%; }

  /* Section labels */
  .tgx-label {
    display: block;
    font-size: .64rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--muted);
    padding: 8px 10px 4px;
  }
  .tgx-label:first-child { padding-top: 2px; }

  /* Temperature row inside popover */
  .tgx-temp {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 6px 10px 9px;
    box-sizing: border-box;
    width: 100%;
  }
  .tgx-temp svg { color: var(--muted); flex-shrink: 0; }
  .tgx-temp-name { font-size: .76rem; font-weight: 600; color: var(--text); flex-shrink: 0; }
  .tgx-temp input[type=range] {
    -webkit-appearance: none; appearance: none;
    flex: 1 1 auto; min-width: 0; width: auto;
    height: 3px; border-radius: 2px;
    background: var(--border); outline: none; cursor: pointer;
  }
  .tgx-temp input[type=range]::-webkit-slider-thumb {
    -webkit-appearance: none; appearance: none;
    width: 13px; height: 13px; border-radius: 50%;
    background: var(--primary); cursor: pointer;
  }

  /* Chevron flips up when popover open */
  .composer-tool-group.expanded .expand-chevron { transform: rotate(180deg); }
}

@media (max-width: 768px) {
  .composer-tool-btn { padding: 6px 8px !important; }
  .composer-toolbar { border-radius: 0 0 14px 14px !important; }
}

/* ═══════════════════════════════════════════════════════════════
   PHASE 7 — MOBILE COMPLETION
   ═══════════════════════════════════════════════════════════════ */

/* A6 — Bottom navigation removed */

/* A7 — Pull-to-refresh indicator */
#ptr-indicator {
  display: none;
  position: fixed;
  top: calc(52px + env(safe-area-inset-top, 0px));
  left: 50%;
  transform: translateX(-50%);
  z-index: 200;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 20px;
  padding: 6px 14px;
  font-size: .75rem;
  color: var(--muted);
  box-shadow: 0 4px 16px rgba(0,0,0,.12);
  align-items: center;
  gap: 6px;
  white-space: nowrap;
}
#ptr-indicator.show { display: flex; }
#ptr-spinner {
  width: 14px; height: 14px;
  border: 2px solid var(--border);
  border-top-color: var(--primary);
  border-radius: 50%;
}
#ptr-indicator.loading #ptr-spinner { animation: spin .6s linear infinite; }

/* C3 — PWA install button */
#pwa-install-btn {
  display: none;
  align-items: center;
  gap: 5px;
  padding: 5px 10px;
  background: var(--primary);
  color: #fff;
  border: none;
  border-radius: 8px;
  font-size: .72rem;
  font-weight: 700;
  font-family: inherit;
  cursor: pointer;
  white-space: nowrap;
  transition: background .15s;
}
#pwa-install-btn:hover { background: var(--primary-hover, #1d4ed8); }

/* One-time hint pointing at the Install button — richer step-by-step card,
   anchored below the button since this one lives in the top bar rather than
   above the bottom composer (compare #composer-swipe-hint). */
#pwa-install-hint {
  position: absolute;
  right: 0;
  top: 100%;
  margin-top: 10px;
  display: none;
  flex-direction: column;
  gap: 8px;
  width: 250px;
  max-width: calc(100vw - 32px);
  padding: 14px 14px 12px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  box-shadow: 0 8px 28px rgba(0,0,0,.2);
  font-size: .78rem;
  color: var(--text);
  z-index: 60;
  white-space: normal;
}
#pwa-install-hint.show { display: flex; }
/* Little pointer triangle so the card visually anchors to the Install button
   above it, even though it's right-aligned rather than centered. */
#pwa-install-hint::before {
  content: '';
  position: absolute;
  top: -6px;
  right: 14px;
  width: 12px;
  height: 12px;
  background: var(--surface);
  border-left: 1px solid var(--border);
  border-top: 1px solid var(--border);
  transform: rotate(45deg);
}
#pwa-install-hint .pwa-hint-title {
  display: flex;
  align-items: center;
  gap: 7px;
  font-weight: 700;
  font-size: .82rem;
  color: var(--text);
  padding-right: 20px;
}
#pwa-install-hint .pwa-hint-title svg { flex-shrink: 0; color: var(--primary); }
#pwa-install-hint ol {
  margin: 0;
  padding-left: 20px;
  display: flex;
  flex-direction: column;
  gap: 5px;
  color: var(--muted);
  line-height: 1.4;
}
#pwa-install-hint ol li strong { color: var(--text); font-weight: 600; }
#pwa-install-hint .pwa-hint-close {
  position: absolute;
  top: 10px;
  right: 10px;
  flex-shrink: 0;
  display: flex;
  background: none;
  border: none;
  padding: 3px;
  color: var(--muted);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  border-radius: 6px;
}
#pwa-install-hint .pwa-hint-close:hover { background: var(--bg); color: var(--text); }

/* C8 — Offline banner */
#offline-banner {
  display: none;
  position: fixed;
  top: calc(52px + env(safe-area-inset-top, 0px));
  left: 0; right: 0;
  z-index: 500;
  background: #f59e0b;
  color: #fff;
  font-size: .78rem;
  font-weight: 700;
  text-align: center;
  padding: 7px 16px;
  align-items: center;
  justify-content: center;
  gap: 8px;
  box-shadow: 0 2px 8px rgba(0,0,0,.2);
}
#offline-banner.show { display: flex; }
@media (min-width: 769px) {
  #offline-banner { top: 0; }
}

/* A2 — Session swipe-left delete hint */
.session-item {
  overflow: hidden;
  cursor: pointer; /* required for iOS Safari to fire click events in scrollable containers */
}

/* Swipe-right on session row → reveal pin action */
.session-swipe-action-pin {
  position: absolute;
  left: 0; top: 0; bottom: 0;
  background: var(--primary);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 16px;
  font-size: .72rem;
  font-weight: 700;
  pointer-events: none;
  border-radius: 8px 0 0 8px;
  gap: 4px;
}

/* Row content (and the pin reveal panel) track one live custom property set
   from JS on every touchmove, so everything moves together, 1:1 with the
   finger — no separate "snap" state to fall out of sync with. --sw-x is a
   plain px offset, clamped to >= 0 (swipe-left/delete was removed — only
   swipe-right/pin remains). The transition is added only via .swipe-snap,
   which JS toggles on for the release animation and off again during
   dragging — that's what makes the drag itself feel direct instead of
   laggy/binary. */
.session-item > *:not(.session-swipe-action-pin) {
  transform: translateX(var(--sw-x, 0px));
}
/* Extra -2px past -100% (not just flush with the clip edge) so the panel's
   right edge is safely inside .session-item's overflow:hidden region at
   rest — landing it exactly on the clip boundary let a 1px hairline of its
   var(--primary) background bleed through on every row via sub-pixel
   rounding (visible as a thin colored line on the left edge of every
   session item, active or not, desktop or touch). */
.session-swipe-action-pin { transform: translateX(calc(-100% - 2px + var(--sw-x, 0px))); }
.session-item.swipe-snap > *,
.session-item.swipe-snap .session-swipe-action-pin {
  transition: transform .22s cubic-bezier(.22,1,.36,1);
}

/* ═══════════════════════════════════════════════════════════════
   PHASE 6 — QUICK WINS
   ═══════════════════════════════════════════════════════════════ */

/* A5 — Safe-area insets (extended) */
.chat-input-wrap {
  padding-bottom: max(10px, env(safe-area-inset-bottom)) !important;
}

/* A8 — Adaptive font sizing */
@media (max-width: 480px) {
  .msg-bubble, .msg-content { font-size: .92rem !important; }
  .welcome-screen h2 { font-size: 1.15rem !important; }
}
@media (min-width: 1440px) {
  .msg-bubble { font-size: .96rem; line-height: 1.75; }
}
/* Guest welcome fills the whole chat panel, edge-to-edge, at every width.
   Class is toggled by _showGuestWelcome/_hideGuestWelcome so real chat keeps its padding. */
.chat-messages.gw-active {
  max-width: 100% !important;
  margin: 0 !important;
  padding: 0 !important;
}

/* B4 — Skip-to-content */
.skip-link {
  position: absolute;
  top: -100px;
  left: 8px;
  z-index: 99999;
  background: var(--primary);
  color: #fff;
  padding: 8px 16px;
  border-radius: 0 0 8px 8px;
  font-size: .85rem;
  font-weight: 700;
  text-decoration: none;
  transition: top .15s;
}
.skip-link:focus { top: 0; }

/* B6 — Reduced motion */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  .cursor-blink { animation: none !important; opacity: 1; }
  .composerPulse { animation: none !important; }
  .typing-indicator .dot { animation: none !important; opacity: .7; }
}

/* C6 — Safari/iOS viewport height fix
   -webkit-fill-available = the visual viewport (excludes browser chrome).
   100dvh alone is correct on iOS 15.4+ but unreliable on older versions.
   The @supports block targets iOS specifically; !important beats the
   height:100dvh!important set in the mobile @media block above. */
@supports (-webkit-touch-callout: none) {
  /* iOS-specific fixes.
     html/body use -webkit-fill-available for correct initial paint height.
     .app-main on mobile uses position:fixed;inset:0 (see mobile @media block)
     so no height override is needed here — fixed positioning tracks the
     visual viewport directly without any dvh or fill-available quirks. */
  html, body {
    height: -webkit-fill-available !important;
  }
  .app-shell {
    height: -webkit-fill-available !important;
    height: 100dvh !important;
    position: relative;
  }
  /* Sidebar: still uses fill-available (off-canvas, keyboard doesn't affect it) */
  @media (max-width: 768px) {
    .app-sidebar {
      height: -webkit-fill-available !important;
    }
  }
}

/* C9 — Page Visibility: dim streaming indicator when hidden (handled via JS) */
.tab-hidden .cursor-blink { animation: none !important; opacity: 0; }

/* C10 — Print stylesheet */
@media print {
  .app-sidebar, .chat-input-wrap, .mobile-topbar,
  .msg-meta, .code-copy-btn, .code-save-btn, .copy-btn,
  #search-overlay, .composer-show-fab, .sidebar-show-btn { display: none !important; }
  .app-shell { display: block !important; }
  .app-main  { display: block !important; width: 100% !important; height: auto !important; overflow: visible !important; }
  .chat-messages { overflow: visible !important; height: auto !important; padding: 0 !important; }
  .msg { max-width: 100% !important; page-break-inside: avoid; margin-bottom: 16px; }
  .msg-bubble { border: 1px solid #ccc !important; border-radius: 8px !important; padding: 12px !important; }
  .code-block-wrap { border: 1px solid #999 !important; }
  .code-block-wrap pre { white-space: pre-wrap !important; }
  body { background: #fff !important; color: #000 !important; }
}

/* E3 — Continue truncated button */
.continue-btn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  margin-top: 10px;
  padding: 7px 16px 7px 14px;
  background: color-mix(in srgb, var(--primary) 9%, transparent);
  border: 1.5px solid color-mix(in srgb, var(--primary) 28%, transparent);
  border-radius: 999px;
  font-size: .78rem;
  font-weight: 650;
  letter-spacing: .01em;
  color: var(--primary);
  cursor: pointer;
  font-family: inherit;
  box-shadow: 0 1px 2px color-mix(in srgb, var(--primary) 12%, transparent);
  transition: background .18s ease, border-color .18s ease,
              box-shadow .18s ease, transform .12s ease;
}
.continue-btn svg {
  transition: transform .18s ease;
}
.continue-btn:hover {
  background: color-mix(in srgb, var(--primary) 16%, transparent);
  border-color: color-mix(in srgb, var(--primary) 55%, transparent);
  box-shadow: 0 3px 10px color-mix(in srgb, var(--primary) 22%, transparent);
  transform: translateY(-1px);
}
.continue-btn:hover svg {
  transform: translateX(3px);
}
.continue-btn:active {
  transform: translateY(0);
  box-shadow: 0 1px 2px color-mix(in srgb, var(--primary) 14%, transparent);
}
.continue-btn:focus-visible {
  outline: 2px solid color-mix(in srgb, var(--primary) 45%, transparent);
  outline-offset: 2px;
}

/* G3 — Table CSV export button
   .table-outer (non-scrolling) is the positioning context for the button
   and its menu; .table-wrap (inside it) is the element that actually
   scrolls horizontally. They must be separate elements — an absolutely
   positioned descendant of a scrolling container is part of that
   container's scrollable overflow and scrolls along with its content, so
   a button placed directly inside .table-wrap drifts away from the
   top-right corner (into the middle, or off-screen) as soon as a table
   wider than the viewport gets scrolled. Keeping the button in the
   non-scrolling outer wrapper instead pins it to the corner regardless of
   the table's scroll position. */
.table-outer { position: relative; }
.table-wrap { overflow-x: auto; margin: 10px 0; }
/* Download icon button — top-right corner of the table */
.table-dl-btn {
  position: absolute;
  top: 6px; right: 6px;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 26px; height: 26px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  cursor: pointer;
  color: var(--muted);
  font-family: inherit;
  transition: border-color .15s, color .15s, opacity .15s;
  opacity: 0;
  z-index: 2;
}
.table-outer:hover .table-dl-btn { opacity: 1; }
.table-dl-btn:hover { border-color: var(--primary); color: var(--primary); }
/* Dropdown */
.table-dl-menu {
  display: none;
  position: absolute;
  top: 36px; right: 6px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: 0 4px 16px rgba(0,0,0,.12);
  z-index: 100;
  min-width: 130px;
  overflow: hidden;
}
.table-dl-menu.open { display: block; }
.table-dl-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  font-size: .78rem;
  color: var(--text);
  cursor: pointer;
  background: none;
  border: none;
  width: 100%;
  text-align: left;
  font-family: inherit;
  transition: background .1s;
}
.table-dl-item:hover { background: var(--hover-bg, rgba(0,0,0,.04)); }

/* Mobile: no hover to reveal the button, so it must be visible by default —
   but sitting directly on top of the header row (the desktop design, which
   relies on a hover-only reveal) overlapped the header text and looked
   misplaced. Reserve a small strip above the table instead, and give the
   button a bit more presence (shadow, rounder) since it's now a permanent
   fixture rather than a hover affordance. */
@media (max-width: 768px) {
  .table-outer { padding-top: 32px !important; }
  .table-dl-btn {
    opacity: 1 !important;
    top: 4px !important;
    right: 4px !important;
    width: 28px !important;
    height: 28px !important;
    border-radius: 8px !important;
    box-shadow: 0 1px 4px rgba(0,0,0,.14);
  }
  .table-dl-menu { top: 38px !important; right: 4px !important; }
}

/* Long table cells (see the tbl.querySelectorAll('td') pass in
   highlightCode()) — clamp to 2 lines with a "More" toggle instead of
   blowing out row height or forcing the whole table to scroll. */
.msg-bubble td.cell-truncated .cell-content {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.msg-bubble td.cell-truncated.cell-expanded .cell-content {
  display: block;
  -webkit-line-clamp: unset;
  overflow: visible;
}
.cell-expand-btn {
  display: block;
  margin-top: 3px;
  padding: 0;
  border: none;
  background: none;
  color: var(--primary);
  font-size: .74rem;
  font-weight: 600;
  cursor: pointer;
  font-family: inherit;
}
.cell-expand-btn:hover { text-decoration: underline; }

.msg-bubble table { border-collapse: collapse; width: 100%; font-size: .84rem; }
.msg-bubble th { background: color-mix(in srgb, var(--primary) 10%, transparent); color: var(--text); padding: 7px 10px; text-align: left; font-weight: 700; border: 1px solid var(--border); }
.msg-bubble td { padding: 6px 10px; border: 1px solid var(--border); color: var(--text); vertical-align: top; }
.msg-bubble tr:nth-child(even) td { background: color-mix(in srgb, var(--surface) 60%, transparent); }

/* Heading scale inside chat bubbles — compact but visually distinct */
.msg-bubble h1 { font-size: 1.3rem; font-weight: 700; margin: .9em 0 .3em; line-height: 1.25; }
.msg-bubble h2 { font-size: 1.15rem; font-weight: 700; margin: .8em 0 .25em; line-height: 1.3; }
.msg-bubble h3 { font-size: 1.05rem; font-weight: 600; margin: .7em 0 .2em; }
.msg-bubble h4 { font-size: .97rem; font-weight: 600; margin: .65em 0 .18em; }
.msg-bubble h5 { font-size: .9rem;  font-weight: 600; margin: .6em 0 .15em; color: var(--muted); }
.msg-bubble h6 { font-size: .84rem; font-weight: 600; margin: .55em 0 .12em; color: var(--muted); }
.msg-bubble h1:first-child, .msg-bubble h2:first-child, .msg-bubble h3:first-child,
.msg-bubble h4:first-child, .msg-bubble h5:first-child, .msg-bubble h6:first-child { margin-top: .1em; }

/* Task-list checkboxes */
.msg-bubble li.md-task { list-style: none; margin-left: -1.4em; display: flex; align-items: flex-start; gap: 6px; }
.msg-bubble li.md-task input[type="checkbox"] { margin-top: 3px; flex-shrink: 0; accent-color: var(--primary); }

/* GitHub-style callout blocks */
.md-callout { border-left: 4px solid; border-radius: 6px; padding: 10px 14px; margin: 10px 0; font-size: .88rem; }
.md-callout-title { font-weight: 700; margin-bottom: 4px; display: flex; align-items: center; gap: 6px; }
.md-callout-body { color: var(--text); }
.md-callout-note      { border-color: #3b82f6; background: color-mix(in srgb, #3b82f6 8%, transparent); }
.md-callout-note .md-callout-title      { color: #3b82f6; }
.md-callout-tip       { border-color: #22c55e; background: color-mix(in srgb, #22c55e 8%, transparent); }
.md-callout-tip .md-callout-title       { color: #22c55e; }
.md-callout-important { border-color: #a855f7; background: color-mix(in srgb, #a855f7 8%, transparent); }
.md-callout-important .md-callout-title { color: #a855f7; }
.md-callout-warning   { border-color: #f59e0b; background: color-mix(in srgb, #f59e0b 8%, transparent); }
.md-callout-warning .md-callout-title   { color: #f59e0b; }
.md-callout-caution   { border-color: #ef4444; background: color-mix(in srgb, #ef4444 8%, transparent); }
.md-callout-caution .md-callout-title   { color: #ef4444; }

/* G4 — Lightbox */
.lightbox-overlay {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 99999;
  background: rgba(0,0,0,.92);
  align-items: center;
  justify-content: center;
  cursor: zoom-out;
  animation: lbIn .15s ease;
}
.lightbox-overlay.open { display: flex; }
@keyframes lbIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}
.lightbox-overlay img {
  max-width: 92vw;
  max-height: 90vh;
  object-fit: contain;
  border-radius: 8px;
  box-shadow: 0 8px 60px rgba(0,0,0,.6);
  cursor: default;
  animation: lbImgIn .18s cubic-bezier(.16,1,.3,1);
}
@keyframes lbImgIn {
  from { transform: scale(.93); }
  to   { transform: scale(1); }
}
.lightbox-close {
  position: absolute;
  top: 14px; right: 14px;
  width: 36px; height: 36px;
  background: rgba(255,255,255,.12);
  border: none;
  border-radius: 50%;
  color: #fff;
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  font-size: 18px;
  transition: background .15s;
}
.lightbox-close:hover { background: rgba(255,255,255,.25); }
/* Make inline images in bubbles clickable */
.msg-bubble img {
  max-width: 100%;
  border-radius: 8px;
  cursor: zoom-in;
  transition: opacity .15s;
  /* Reserve a box before an arbitrary markdown-embedded image's real
     dimensions are known — a generic photo/screenshot-ish guess, just to
     avoid collapsing to ~0 height pre-load. The "auto" prefix is required
     for the browser to switch to the image's own natural ratio once loaded
     — a bare ratio (no "auto") always wins over the intrinsic size and
     would permanently squash/stretch any non-16:9 image, not just reserve
     space pre-load. */
  aspect-ratio: auto 16 / 9;
}
.msg-bubble img:hover { opacity: .9; }

/* Mermaid diagrams render async (renderMermaid() in dashboard.js): the wrap
   starts as a one-line "Rendering diagram…" placeholder, then its innerHTML
   is replaced with the full SVG once ready — often a much taller box. A
   min-height here means that swap is a smaller, less jarring scrollHeight
   change instead of "one text line" -> "full diagram" with no reservation. */
.mermaid-wrap { min-height: 160px; }

/* G6 — Quote past message button */
.quote-btn {
  display: none;
  background: none; border: none; cursor: pointer;
  color: var(--muted); padding: 3px 6px; border-radius: 5px;
  font-size: .72rem; align-items: center; gap: 4px;
  transition: background .15s, color .15s;
  font-family: inherit;
}
.msg:hover .quote-btn { display: inline-flex; }
.quote-btn:hover { background: var(--bg); color: var(--primary); }

/* G6 — Quote-reply context card (shown above the composer textarea) */
.quote-context {
  display: flex;
  align-items: stretch;
  gap: 0;
  margin: 0 0 8px 0;
  background: linear-gradient(90deg,
    color-mix(in srgb, var(--primary) 10%, transparent) 0%,
    color-mix(in srgb, var(--primary) 5%, transparent) 100%);
  border: 1px solid color-mix(in srgb, var(--primary) 25%, var(--border));
  border-radius: 10px;
  overflow: hidden;
  position: relative;
  animation: quoteSlideIn .18s cubic-bezier(.16,1,.3,1);
}
@keyframes quoteSlideIn {
  from { opacity: 0; transform: translateY(-4px); max-height: 0; }
  to   { opacity: 1; transform: translateY(0); max-height: 200px; }
}
.quote-context-bar {
  width: 3px;
  background: var(--primary);
  flex-shrink: 0;
}
.quote-context-body {
  flex: 1;
  min-width: 0;
  padding: 8px 12px;
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.quote-context-header {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: .72rem;
  font-weight: 600;
  color: var(--primary);
  text-transform: uppercase;
  letter-spacing: .04em;
}
.quote-context-header svg { color: var(--primary); flex-shrink: 0; }
.quote-context-text {
  font-size: .82rem;
  color: var(--text);
  opacity: .85;
  line-height: 1.45;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
  text-overflow: ellipsis;
  word-break: break-word;
  white-space: pre-wrap;
}
.quote-context-close {
  background: none;
  border: none;
  cursor: pointer;
  color: var(--muted);
  padding: 0 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  border-radius: 0;
  transition: background .15s, color .15s;
  align-self: stretch;
}
.quote-context-close:hover { background: color-mix(in srgb, var(--primary) 12%, transparent); color: var(--danger); }
.quote-context-close:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }

[data-theme="dark"] .quote-context {
  background: linear-gradient(90deg,
    color-mix(in srgb, var(--primary) 18%, transparent) 0%,
    color-mix(in srgb, var(--primary) 8%, transparent) 100%);
}

/* G7 — Collapsible code blocks */
.code-block-wrap.collapsed pre { max-height: 160px; overflow: hidden; position: relative; }
.code-block-wrap.collapsed pre::after {
  content: '';
  position: absolute;
  bottom: 0; left: 0; right: 0;
  height: 60px;
  background: linear-gradient(transparent, #1e1e2e);
  pointer-events: none;
}
.code-collapse-btn {
  display: block;
  width: 100%;
  padding: 6px 14px;
  background: #161625;
  border: none;
  border-top: 1px solid rgba(255,255,255,.07);
  color: rgba(255,255,255,.45);
  font-size: .7rem;
  font-family: inherit;
  cursor: pointer;
  text-align: center;
  transition: background .15s, color .15s;
  letter-spacing: .04em;
}
.code-collapse-btn:hover { background: rgba(255,255,255,.05); color: rgba(255,255,255,.7); }

/* H7 — Duplicate: now inside the ⋯ dropdown, no longer a standalone hover button */

/* H6 — Session hover preview tooltip */
.session-item { position: relative; }
.session-preview-tip {
  display: none;
  position: absolute;
  left: calc(100% + 8px);
  top: 0;
  z-index: 300;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 10px 12px;
  width: 220px;
  font-size: .76rem;
  color: var(--muted);
  line-height: 1.5;
  box-shadow: 0 6px 24px rgba(0,0,0,.14);
  pointer-events: none;
  word-break: break-word;
  white-space: normal;
}
.session-item:hover .session-preview-tip { display: block; }
@media (max-width: 768px) {
  .session-preview-tip { display: none !important; }
}

/* I4 — Recent prompts dropdown */
.recent-prompts {
  position: absolute;
  bottom: calc(100% + 8px);
  left: 14px; right: 14px;
  background: var(--surface);
  border: 1.5px solid var(--primary);
  border-radius: 12px;
  box-shadow: 0 8px 32px rgba(0,0,0,.15);
  z-index: 500;
  overflow: hidden;
  animation: scPickerIn .18s cubic-bezier(.16,1,.3,1);
  max-height: 280px;
  display: flex;
  flex-direction: column;
}
.recent-prompts-header {
  display: flex; align-items: center; gap: 7px;
  padding: 8px 12px 6px;
  font-size: .72rem; font-weight: 700;
  color: var(--primary);
  border-bottom: 1px solid var(--border);
  text-transform: uppercase; letter-spacing: .05em;
  background: color-mix(in srgb, var(--primary) 5%, transparent);
}
.recent-prompts-list { overflow-y: auto; padding: 5px; display: flex; flex-direction: column; gap: 2px; }
.recent-prompt-item {
  padding: 8px 10px; border-radius: 8px; cursor: pointer;
  font-size: .83rem; color: var(--text);
  display: flex; align-items: center; gap: 7px;
  transition: background .12s;
}
.recent-prompt-item:hover { background: color-mix(in srgb, var(--primary) 10%, transparent); color: var(--primary); }
.recent-prompt-text { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; }
.recent-prompt-kind {
  flex-shrink: 0; font-size: .62rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: .04em; padding: 1px 6px; border-radius: 5px;
  color: var(--muted); background: color-mix(in srgb, var(--text) 8%, transparent);
}
.recent-prompt-kind.kind-image { color: #8b5cf6; background: color-mix(in srgb, #8b5cf6 14%, transparent); }
.recent-prompt-kind.kind-video { color: #ec4899; background: color-mix(in srgb, #ec4899 14%, transparent); }
.recent-prompt-kind.kind-audio { color: #06b6d4; background: color-mix(in srgb, #06b6d4 14%, transparent); }

/* I6 — Slash picker preview pane */
.sc-picker-preview {
  padding: 8px 12px;
  border-top: 1px solid var(--border);
  font-size: .76rem;
  color: var(--muted);
  line-height: 1.5;
  background: color-mix(in srgb, var(--surface) 80%, var(--bg));
  max-height: 70px;
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  word-break: break-word;
}

/* K4 — Conversation summary button */
.summary-result {
  margin: 8px 0 0;
  padding: 10px 14px;
  background: color-mix(in srgb, var(--primary) 6%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--primary) 20%, transparent);
  border-radius: 10px;
  font-size: .82rem;
  color: var(--text);
  line-height: 1.6;
  display: none;
}
.summary-result.show { display: block; }

/* ── Phase 8 — Accessibility Deep Dive ─────────────────────────────────────── */

/* B5 — High-contrast: automatic (prefers-contrast) + manual toggle */
@media (prefers-contrast: more) {
  /* Boost saturation/lightness only — keep --primary-h so every accent
     token (buttons, gradients, rings) still derives from the user's chosen
     theme instead of being forced to a fixed blue that ignores it. */
  :root {
    --border: #000 !important;
    --text:   #000 !important;
    --muted:  #333 !important;
    --bg:     #fff !important;
    --surface:#fff !important;
    --primary-s: 100% !important;
    --primary-l: 32% !important;
    /* --grad-brand hardcodes its own 88%/58%→90%/48% stops (ignores
       --primary-s/-l), so gradient-filled buttons like #new-chat-btn
       wouldn't pick up the contrast boost above without this override. */
    --grad-brand: var(--primary) !important;
  }
  [data-theme="dark"], html[data-theme="dark"] {
    --border: #fff !important;
    --text:   #fff !important;
    --muted:  #ccc !important;
    --bg:     #000 !important;
    --surface:#111 !important;
    --primary-s: 100% !important;
    --primary-l: 72% !important;
    --grad-brand: var(--primary) !important;
  }
}
/* Manual high-contrast toggle (.hc on <html>) — same approach: keep
   --primary-h so buttons/gradients still match the active theme's hue. */
html.hc {
  --border: #000 !important;
  --text:   #000 !important;
  --muted:  #333 !important;
  --bg:     #fff !important;
  --surface:#fff !important;
  --primary-s: 100% !important;
  --primary-l: 32% !important;
  --grad-brand: var(--primary) !important;
}
html.hc[data-theme="dark"] {
  --border: #fff !important;
  --text:   #fff !important;
  --muted:  #ccc !important;
  --bg:     #000 !important;
  --surface:#111 !important;
  --primary-s: 100% !important;
  --primary-l: 72% !important;
  --grad-brand: var(--primary) !important;
}
html.hc .msg-bubble,
html.hc .session-item,
html.hc .sf-footer,
html.hc .app-sidebar,
html.hc .chat-input-wrap {
  border-color: var(--border) !important;
  outline: 1px solid var(--border);
}
html.hc a:focus,
html.hc button:focus,
html.hc [tabindex="0"]:focus {
  outline: 3px solid var(--primary) !important;
  outline-offset: 2px !important;
}

/* Global keyboard-focus visibility for interactive elements */
button:focus-visible,
a:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible,
[role="button"]:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

/* B7 — Keyboard-navigable session items */
.session-item[tabindex] { outline: none; }
.session-item[tabindex]:focus {
  background: color-mix(in srgb, var(--primary) 10%, var(--surface));
  outline: 2px solid var(--primary);
  outline-offset: -2px;
}
.session-item[tabindex]:focus .session-more-btn { opacity: 1; }

/* B9 — Font-size preference steps */
html.fs-sm { font-size: 13px; }
html.fs-md { font-size: 15px; }   /* default */
html.fs-lg { font-size: 17px; }
html.fs-xl { font-size: 19px; }

/* B5 + B9 — Sidebar accessibility bar */
.sidebar-a11y-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 6px 10px;
  border-top: 1px solid var(--border);
  gap: 6px;
  flex-shrink: 0;
}
.a11y-btn-group {
  display: flex;
  align-items: center;
  gap: 3px;
}
.a11y-btn {
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 6px;
  padding: 3px 8px;
  font-size: .72rem;
  font-weight: 600;
  cursor: pointer;
  line-height: 1.4;
  transition: background .15s, color .15s;
}
.a11y-btn:hover { background: var(--border); }
.a11y-btn.active {
  background: var(--primary);
  color: #fff;
  border-color: var(--primary);
}
/* ── Sidebar new-chat + search area ─────────────────────────────────────────── */
.sidebar-new-chat {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 8px 10px;
  flex-shrink: 0;
}
/* ── Session search box ──────────────────────────────────────────────────────── */
.session-search-wrap {
  position: relative;
  display: flex;
  align-items: center;
  width: 100%;
  background: color-mix(in srgb, var(--border) 45%, transparent);
  border-radius: 100px;
}
.session-search-icon {
  position: absolute;
  left: 10px;
  color: var(--muted);
  pointer-events: none;
  flex-shrink: 0;
  opacity: .55;
  transition: opacity .2s, color .2s;
}
.session-search-wrap:focus-within .session-search-icon {
  opacity: 1;
  color: var(--primary);
}
/* Use input.session-search (specificity 0,1,1) to beat app.css's input[type="search"] (0,1,1 same)
   but inline <style> loads after the <link>, so equal specificity resolves in our favour. */
input.session-search {
  width: 100%;
  padding: 7px 78px 7px 30px;
  font-size: .78rem;
  background: transparent !important;
  border: none !important;
  border-radius: 100px !important;
  box-shadow: none !important;
  color: var(--text);
  outline: none;
  transition: background .2s;
  min-width: 0;
  -webkit-appearance: none;
  appearance: none;
}
input.session-search::placeholder { color: var(--muted); opacity: .8; }
.session-search-wrap:hover {
  background: color-mix(in srgb, var(--border) 70%, transparent);
}
.session-search-wrap:focus-within {
  background: var(--bg);
  outline: 1.5px solid color-mix(in srgb, var(--primary) 55%, transparent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary) 10%, transparent);
}
input.session-search::-webkit-search-cancel-button { cursor: pointer; }
.session-search-global-btn {
  position: absolute;
  right: 4px;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  border: none;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
  padding: 0;
  opacity: .5;
  transition: opacity .15s, background .15s, color .15s, transform .15s;
  flex-shrink: 0;
}
/* 3 icon buttons now live in this rail (search-in-chat, global search,
   notifications) — each needs its own slot with real spacing between them,
   or they stack on top of each other / crowd out clicks. Previously there
   were only 2 slots (right:5 default + #chat-search-btn's right:27);
   #notif-bell-btn had no override at all and silently landed on top of
   #global-search-btn's right:5, making both unclickable/indistinguishable
   the moment the notification tray (Phase 62) was added. 24px steps give
   each 20px button a 4px gap on both sides instead of touching edges. */
#global-search-btn.session-search-global-btn { right: 4px; }
#chat-search-btn.session-search-global-btn   { right: 28px; }
#notif-bell-btn.session-search-global-btn    { right: 52px; }
.session-search-wrap:focus-within .session-search-global-btn { opacity: .75; }
.session-search-global-btn:hover { transform: scale(1.08); }
.session-search-global-btn:hover {
  opacity: 1;
  background: color-mix(in srgb, var(--primary) 12%, transparent);
  color: var(--primary);
}
.a11y-label {
  font-size: .65rem;
  color: var(--muted);
  letter-spacing: .04em;
  text-transform: uppercase;
}

/* ── Phase 9 — Token & Cost Awareness ──────────────────────────────────────── */

/* F3 — Context meter strip above composer */
#ctx-meter-wrap {
  display: none;
  align-items: center;
  gap: 8px;
  padding: 3px 14px;
  font-size: .7rem;
  color: var(--muted);
  flex-shrink: 0;
}
#ctx-meter-wrap.visible { display: flex; }
#ctx-meter-track {
  flex: 1;
  height: 4px;
  background: var(--border);
  border-radius: 99px;
  overflow: hidden;
}
#ctx-meter-fill {
  height: 100%;
  border-radius: 99px;
  background: var(--primary);
  transition: width .4s ease, background .3s;
  min-width: 2px;
}
#ctx-meter-fill.warn  { background: #f59e0b; }
#ctx-meter-fill.crit  { background: #ef4444; }
#ctx-meter-label {
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
  font-size: .68rem;
}
#ctx-meter-warning {
  display: none;
  align-items: center;
  gap: 3px;
  padding: 1px 6px;
  border-radius: 99px;
  font-size: .65rem;
  font-weight: 700;
  white-space: nowrap;
}
#ctx-meter-warning.warn { display: inline-flex; background: #fef3c7; color: #92400e; }
#ctx-meter-warning.crit { display: inline-flex; background: #fee2e2; color: #991b1b; }

/* F4 — Cost chip */
#ctx-cost-chip {
  font-size: .65rem;
  color: var(--muted);
  white-space: nowrap;
  padding: 0 4px;
  border-left: 1px solid var(--border);
  margin-left: 2px;
}

#composer-token-count { display: none !important; }

/* F2 — Per-message token badge */
.msg-tokens {
  font-size: .67rem;
  color: var(--muted);
  opacity: .7;
  font-variant-numeric: tabular-nums;
  margin-left: 2px;
  white-space: nowrap;
}

/* ── Auto-memory "Memory updated" chip + undo popover ────────────────────────
   Sits in .msg-meta next to the token badge/copy button, muted like the rest
   of that row until hovered/clicked so it doesn't compete with the reply. */
.mem-chip-wrap { position: relative; display: inline-flex; }
.mem-chip {
  background: none; border: none; cursor: pointer;
  color: var(--muted); font-size: .68rem; opacity: .75;
  padding: 2px 5px; border-radius: 4px; white-space: nowrap;
  transition: opacity .15s, background .15s, color .15s;
}
.mem-chip:hover { opacity: 1; background: var(--bg); color: var(--text); }
.mem-popover {
  display: none;
  position: absolute; bottom: calc(100% + 6px); left: 0;
  min-width: 220px; max-width: 320px;
  background: var(--surface); border: 1px solid var(--border); border-radius: 10px;
  box-shadow: 0 6px 24px rgba(0,0,0,.18);
  padding: 6px; z-index: 40;
}
.mem-popover.visible { display: block; }
.mem-popover-item {
  display: flex; align-items: flex-start; gap: 8px;
  padding: 6px 6px; border-radius: 6px; font-size: .78rem;
}
.mem-popover-item:hover { background: var(--bg); }
.mem-popover-text { flex: 1; color: var(--text); line-height: 1.4; }
.mem-popover-item.mem-undone .mem-popover-text { color: var(--muted); font-style: italic; }
.mem-undo-btn {
  flex-shrink: 0; background: none; border: none; cursor: pointer;
  color: var(--primary); font-weight: 700; font-size: .72rem;
  padding: 2px 4px; border-radius: 4px;
}
.mem-undo-btn:hover { text-decoration: underline; }

/* ── Phase 10 — Session Organization ───────────────────────────────────────── */

/* H2 — Archive button + archived view link */
.session-item-archive {
  display: none;
  align-items: center;
  justify-content: center;
  width: 22px; height: 22px;
  border: none; background: transparent;
  color: var(--muted);
  border-radius: 5px;
  cursor: pointer;
  padding: 0;
  transition: color .15s, background .15s;
  flex-shrink: 0;
}
/* Archive button only used in archived-list view now — not in main session items */
.session-item-archive:hover { color: var(--primary); background: color-mix(in srgb, var(--primary) 10%, transparent); }

/* ── Session ⋯ more-actions button ──────────────────────────────────────────── */
.session-more-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px; height: 28px;
  min-width: 28px;
  border: none;
  background: transparent;
  color: var(--muted);
  border-radius: 6px;
  cursor: pointer;
  padding: 0;
  opacity: 0;
  transition: opacity .15s, color .15s, background .15s;
  flex-shrink: 0;
}
.session-item:hover .session-more-btn,
.session-item.active .session-more-btn,
.session-item[tabindex]:focus .session-more-btn { opacity: 1; }
.session-more-btn:hover { color: var(--text); background: var(--hover-bg, rgba(0,0,0,.06)); }
.session-rename-input {
  flex: 1; min-width: 0; width: 100%;
  background: var(--bg); border: 1.5px solid var(--primary);
  border-radius: 5px; padding: 1px 5px;
  font-size: .82rem; font-family: inherit; color: var(--text);
  outline: none; box-shadow: 0 0 0 2px color-mix(in srgb,var(--primary) 18%,transparent);
}
.session-item.is-renaming .session-item-actions { display: none !important; }

/* ── Session actions dropdown menu ──────────────────────────────────────────── */
#session-actions-menu {
  position: fixed;
  z-index: 9100;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: 0 8px 32px rgba(0,0,0,.18);
  padding: 4px;
  min-width: 168px;
  display: none;
  animation: scPickerIn .14s cubic-bezier(.16,1,.3,1);
}
#session-actions-menu.open { display: block; }
.sam-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 12px;
  border-radius: 7px;
  font-size: .83rem;
  color: var(--text);
  cursor: pointer;
  border: none;
  background: transparent;
  width: 100%;
  text-align: left;
  font-family: inherit;
  transition: background .12s;
  white-space: nowrap;
}
.sam-item:hover { background: var(--hover-bg, rgba(0,0,0,.05)); }
.sam-item svg { flex-shrink: 0; color: var(--muted); }
.sam-item.danger { color: var(--danger, #ef4444); }
.sam-item.danger svg { color: var(--danger, #ef4444); }
.sam-sep { height: 1px; background: var(--border); margin: 3px 4px; }

/* J1 — "Show more" batch button, appended inside #session-list itself (not a
   sibling row) — it scrolls with the list and disappears once every session
   has been rendered, unlike .archived-toggle-row below. */
.session-load-more-btn {
  display: block;
  width: 100%;
  margin-top: 2px;
  padding: 8px 10px;
  font-size: .72rem;
  font-weight: 600;
  color: var(--primary);
  background: transparent;
  border: 1px dashed var(--border);
  border-radius: var(--r-md, 8px);
  cursor: pointer;
  text-align: center;
  transition: background .15s, border-color .15s;
}
.session-load-more-btn:hover {
  background: color-mix(in srgb, var(--primary) 8%, transparent);
  border-color: var(--primary);
}

.archived-toggle-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 6px 10px;
  font-size: .72rem;
  color: var(--muted);
  cursor: pointer;
  border-top: 1px solid var(--border);
  transition: color .15s;
  user-select: none;
  /* Sibling of the flex:1 #session-list inside .app-sidebar — without this it
     defaults to flex-shrink:1 and gets squeezed to nothing (or clipped away
     entirely) once the chat list is long. Only #session-list should ever
     give up space; every other sidebar row is fixed furniture. */
  flex-shrink: 0;
}
.archived-toggle-row:hover { color: var(--primary); }
.archived-toggle-row svg { flex-shrink: 0; }
#archived-count-badge {
  background: var(--border);
  border-radius: 99px;
  padding: 0 5px;
  font-size: .65rem;
  font-weight: 700;
  min-width: 16px;
  text-align: center;
}

/* H4 — Drag-to-reorder */
.session-item.dragging {
  opacity: .4;
  cursor: grabbing !important;
}
.session-item[draggable="true"] { cursor: grab; }
.session-item.drag-over-top {
  box-shadow: 0 -2px 0 var(--primary) !important;
}
.session-item.drag-over-bottom {
  box-shadow: 0 2px 0 var(--primary) !important;
}

/* H5 — Global search modal */
#global-search-modal {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 3000;
  background: rgba(0,0,0,.45);
  align-items: flex-start;
  justify-content: center;
  padding-top: 80px;
}
#global-search-modal.open { display: flex; }
#global-search-box {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  width: min(640px, 96vw);
  max-height: 70vh;
  display: flex;
  flex-direction: column;
  box-shadow: 0 20px 60px rgba(0,0,0,.25);
  overflow: hidden;
}
#global-search-input-wrap {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 14px 16px;
  border-bottom: 1px solid var(--border);
}
#global-search-input-wrap svg { color: var(--muted); flex-shrink: 0; }
#global-search-q {
  flex: 1;
  border: none;
  background: transparent;
  font-size: 1rem;
  color: var(--text);
  outline: none;
}
#global-search-q::placeholder { color: var(--muted); }
#global-search-close {
  border: none; background: transparent;
  color: var(--muted); cursor: pointer;
  font-size: 1.1rem; line-height: 1;
  padding: 2px 6px;
  border-radius: 4px;
  transition: color .15s;
}
#global-search-close:hover { color: var(--text); }
#global-search-results {
  overflow-y: auto;
  flex: 1;
  padding: 8px 0;
}
.gs-result-item {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 10px 16px;
  cursor: pointer;
  border-bottom: 1px solid color-mix(in srgb, var(--border) 50%, transparent);
  transition: background .12s;
}
.gs-result-item:hover { background: color-mix(in srgb, var(--primary) 6%, var(--surface)); }
.gs-result-session { font-size: .72rem; font-weight: 700; color: var(--primary); }
.gs-result-role    { font-size: .65rem; color: var(--muted); text-transform: capitalize; }
.gs-result-snippet { font-size: .82rem; color: var(--text); line-height: 1.45; }
.gs-result-date    { font-size: .65rem; color: var(--muted); }
.gs-result-snippet mark {
  background: color-mix(in srgb, var(--primary) 25%, transparent);
  color: var(--text);
  border-radius: 2px;
  padding: 0 1px;
}
#global-search-status {
  padding: 24px 16px;
  text-align: center;
  font-size: .82rem;
  color: var(--muted);
}

/* H8 — Bulk toolbar */
.bulk-toolbar {
  display: flex;
  align-items: center;
  flex-wrap: nowrap;
  gap: 4px;
  padding: 5px 8px;
  border-bottom: 1px solid var(--border);
  background: var(--surface);
  overflow: hidden;
  /* Sibling of the flex:1 #session-list — see .archived-toggle-row. */
  flex-shrink: 0;
}
.bulk-toolbar .btn {
  padding: 3px 8px;
  font-size: .7rem;
  white-space: nowrap;
  flex-shrink: 0;
}
#bulk-count {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: .72rem;
}

/* H8 — Bulk export button */
#bulk-export-btn {
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 7px;
  padding: 3px 8px;
  font-size: .7rem;
  font-weight: 600;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 4px;
  transition: background .15s;
  flex-shrink: 0;
  white-space: nowrap;
}
#bulk-export-btn:hover { background: var(--border); }

/* ── Phase 11 — Rich Content Rendering ─────────────────────────────────────── */

/* G5 — Image gallery grid */
.img-gallery {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
  gap: 6px;
  margin: 8px 0;
}
.img-gallery .gallery-thumb {
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: 8px;
  cursor: zoom-in;
  border: 2px solid transparent;
  transition: border-color .15s, transform .15s;
}
.img-gallery .gallery-thumb:hover { border-color: var(--primary); transform: scale(1.03); }

/* G5 — Lightbox gallery navigation */
.lightbox-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  background: rgba(0,0,0,.55);
  border: none;
  color: #fff;
  font-size: 1.6rem;
  line-height: 1;
  width: 44px; height: 44px;
  border-radius: 50%;
  cursor: pointer;
  display: none;
  align-items: center;
  justify-content: center;
  transition: background .15s;
  z-index: 1;
  user-select: none;
}
.lightbox-nav:hover { background: rgba(0,0,0,.8); }
#lightbox-prev { left: 16px; }
#lightbox-next { right: 16px; }
#lightbox.gallery-mode .lightbox-nav { display: flex; }
#lightbox-counter {
  position: absolute;
  bottom: 14px;
  left: 50%;
  transform: translateX(-50%);
  background: rgba(0,0,0,.55);
  color: #fff;
  border-radius: 99px;
  padding: 3px 12px;
  font-size: .75rem;
  display: none;
  white-space: nowrap;
}
#lightbox.gallery-mode #lightbox-counter { display: block; }

/* G8 — Composer syntax preview */
#composer-code-preview {
  display: none;
  margin: 0 4px 4px;
  border: 1px solid var(--border);
  border-radius: 8px;
  overflow: hidden;
  max-height: 180px;
  overflow-y: auto;
  font-size: .78rem;
}
#composer-code-preview.visible { display: block; }
#composer-code-preview pre {
  margin: 0;
  padding: 10px 14px;
  background: var(--surface);
  overflow-x: auto;
}
#composer-code-preview .code-preview-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 4px 10px;
  background: color-mix(in srgb, var(--border) 60%, transparent);
  font-size: .67rem;
  color: var(--muted);
  font-family: var(--font-mono, monospace);
}

/* G9 — Diff rendering */
.diff-block { font-family: var(--font-mono, 'Fira Code', monospace); font-size: .82rem; line-height: 1.55; overflow-x: auto; }
.diff-line   { display: flex; white-space: pre; min-width: 0; }
.diff-line-num { color: var(--muted); user-select: none; min-width: 36px; padding-right: 10px; text-align: right; flex-shrink: 0; opacity: .5; font-size: .75rem; padding-top: 1px; }
.diff-line-add  { background: color-mix(in srgb, #22c55e 10%, transparent); color: #15803d; }
.diff-line-del  { background: color-mix(in srgb, #ef4444 10%, transparent); color: #b91c1c; }
.diff-line-meta { background: color-mix(in srgb, #6366f1 8%, transparent); color: #4f46e5; font-weight: 600; }
[data-theme="dark"] .diff-line-add  { color: #86efac; background: rgba(34,197,94,.12); }
[data-theme="dark"] .diff-line-del  { color: #fca5a5; background: rgba(239,68,68,.12); }
[data-theme="dark"] .diff-line-meta { color: #a5b4fc; background: rgba(99,102,241,.10); }
.diff-line-sig  { padding: 0 10px; flex: 1; }

/* G10 — Citation chips */
.citation-chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  vertical-align: super;
  font-size: .6em;
  font-weight: 700;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  border-radius: 99px;
  background: color-mix(in srgb, var(--primary) 15%, transparent);
  color: var(--primary);
  cursor: pointer;
  margin: 0 1px;
  border: 1px solid color-mix(in srgb, var(--primary) 30%, transparent);
  text-decoration: none;
  transition: background .12s;
  line-height: 1;
}
.citation-chip:hover { background: color-mix(in srgb, var(--primary) 25%, transparent); }
/* Inline "[4, 5]" reference links (see _linkifyInlineCitations) — jump to the
   matching numbered chip in the Sources strip at the bottom of the reply. */
.citation-ref-link {
  color: var(--primary);
  font-weight: 700;
  text-decoration: none;
  cursor: pointer;
}
.citation-ref-link:hover { text-decoration: underline; }
.citation-chip.citation-pulse {
  animation: citation-pulse .6s ease-in-out 2;
}
@keyframes citation-pulse {
  0%, 100% { background: color-mix(in srgb, var(--primary) 15%, transparent); }
  50% { background: color-mix(in srgb, var(--primary) 45%, transparent); }
}
/* Deep Research — inline progress card shown while a background research
   job is running (see submitDeepResearch/_drRenderCard in dashboard.js). */
.dr-progress-card {
  margin-top: 6px;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--bg-secondary, var(--bg));
  font-size: .85rem;
}
.dr-progress-row {
  display: flex;
  align-items: center;
  gap: 8px;
}
.dr-progress-text {
  color: var(--text);
}
.dr-progress-meta {
  margin-top: 4px;
  margin-left: 22px;
  font-size: .76rem;
  color: var(--muted);
}
.dr-icon-error { color: var(--danger, #e5484d); }
.dr-icon-done  { color: var(--success, #30a46c); }
.dr-spinner {
  width: 14px;
  height: 14px;
  border: 2px solid var(--border);
  border-top-color: var(--primary);
  border-radius: 50%;
  flex: 0 0 auto;
  animation: dr-spin .8s linear infinite;
}
@keyframes dr-spin { to { transform: rotate(360deg); } }
.dr-cancel-btn {
  margin-top: 8px;
  margin-left: 22px;
  padding: 3px 10px;
  font-size: .76rem;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
}
.dr-cancel-btn:hover {
  color: var(--text);
  border-color: var(--muted);
}

.citation-strip {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin-top: 10px;
  margin-bottom: 10px;
  padding-top: 8px;
  border-top: 1px solid var(--border);
}
.citation-label {
  font-size: .72rem;
  font-weight: 600;
  color: var(--muted);
  margin-right: 2px;
}
.citation-strip .citation-chip {
  vertical-align: middle;
  font-size: .72rem;
  height: auto;
  min-width: 0;
  padding: 2px 8px;
  border-radius: 99px;
  gap: 4px;
}
.citation-strip .citation-chip-doc {
  cursor: default;
}
.citation-strip .citation-num {
  font-size: .85em;
}
.citation-footnotes {
  margin-top: 12px;
  padding-top: 10px;
  border-top: 1px solid var(--border);
  font-size: .78rem;
  color: var(--muted);
  line-height: 1.6;
}
.citation-footnote-item {
  display: flex;
  gap: 6px;
  margin-bottom: 3px;
}
.citation-footnote-num {
  color: var(--primary);
  font-weight: 700;
  flex-shrink: 0;
  min-width: 20px;
}

/* ── Phase 12 — Composer Enhancements ──────────────────────────────────────── */

/* D4 — Voice input */
@keyframes micPulse { 0%,100%{box-shadow:0 0 0 0 rgba(239,68,68,.5)} 50%{box-shadow:0 0 0 6px rgba(239,68,68,0)} }
.mic-btn { transition: color .15s, background .15s; }
.mic-btn.recording { color: #ef4444 !important; animation: micPulse 1.2s infinite; }

/* D5 — Voice output */
.speak-btn {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 7px; border-radius: 6px; border: 1px solid var(--border);
  background: transparent; color: var(--muted); font-size: .67rem;
  cursor: pointer; transition: color .15s, background .15s;
}
.speak-btn:hover { color: var(--primary); background: color-mix(in srgb, var(--primary) 8%, transparent); }
.speak-btn.speaking { color: var(--primary); border-color: var(--primary); }

/* (Legacy "I3" prompt-library modal styles removed — the modal and its JS
   were superseded by the DB-backed Phase 53 template marketplace #pl-modal,
   which has its own styles below.) */

/* I8 — Markdown preview panel */
#md-preview-panel {
  display: none; margin: 0 4px 4px;
  border: 1px solid var(--border); border-radius: 8px;
  padding: 12px 16px; background: var(--surface);
  font-size: .88rem; line-height: 1.65; color: var(--text);
  max-height: 260px; overflow-y: auto;
}
#md-preview-panel.visible { display: block; }
#md-preview-panel p { margin: 0 0 6px; }
#md-preview-btn.active { color: var(--primary) !important; background: color-mix(in srgb, var(--primary) 10%, transparent) !important; }

/* ── Phase 13 — PWA / Multi-tab sync ───────────────────────────────────────── */
/* (Mostly JS/file-based — no extra CSS needed) */

/* ── Phase 14 — Performance ─────────────────────────────────────────────────── */
/* J2 — Lazy session skeleton shimmer already in Phase 1; no extra CSS */
/* J4 — Image compression indicator */
#img-compress-badge {
  display: none; position: absolute; bottom: 6px; left: 6px;
  background: rgba(0,0,0,.65); color: #fff; font-size: .65rem;
  border-radius: 4px; padding: 2px 6px; pointer-events: none;
}
#img-compress-badge.visible { display: block; }

/* ── Phase 15 — Sharing ──────────────────────────────────────────────────────── */
.share-btn {
  display: none; align-items: center; gap: 4px;
  padding: 2px 7px; border-radius: 6px; border: 1px solid var(--border);
  background: transparent; color: var(--muted); font-size: .67rem; cursor: pointer;
  transition: color .15s;
}
.session-item:hover .share-btn { display: inline-flex; }
.share-btn:hover { color: var(--primary); }

/* Share link modal */
#share-modal {
  display: none; position: fixed; inset: 0; z-index: 3200;
  background: rgba(0,0,0,.45); align-items: center; justify-content: center;
}
#share-modal.open { display: flex; }
#share-box {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 14px; width: min(500px, 96vw); padding: 24px;
  box-shadow: 0 20px 60px rgba(0,0,0,.25);
}
#share-box-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; }
#share-box h3 { margin: 0; font-size: .95rem; }
#share-close-btn { background: none; border: none; cursor: pointer; color: var(--muted); padding: 4px; border-radius: 6px; display: flex; align-items: center; justify-content: center; transition: color .15s, background .15s; }
#share-close-btn:hover { color: var(--text); background: var(--bg); }
#share-link-row { display: flex; gap: 8px; align-items: stretch; height: 38px; }
#share-link-input { flex: 1; min-width: 0; height: 100%; box-sizing: border-box; font-size: .82rem; padding: 0 10px; border: 1px solid var(--border); border-radius: 8px; background: var(--bg); color: var(--text); }
#share-copy-btn { height: 100%; box-sizing: border-box; font-size: .82rem; padding: 0 18px; }
#share-expire-row { margin-top: 10px; font-size: .78rem; color: var(--muted); display: flex; align-items: center; gap: 6px; flex-wrap: nowrap; white-space: nowrap; }
#share-expire-sel { font-size: .78rem; padding: 5px 8px; border: 1px solid var(--border); border-radius: 6px; background: var(--bg); color: var(--text); flex-shrink: 0; width: auto; height: 30px; box-sizing: border-box; }
#share-expire-row .btn { font-size: .78rem; padding: 0 12px; white-space: nowrap; flex-shrink: 0; height: 30px; box-sizing: border-box; }
#collab-invite-row { display: flex; gap: 6px; align-items: stretch; margin-top: 6px; height: 38px; }
#collab-email-input { flex: 1; min-width: 0; height: 100%; box-sizing: border-box; font-size: .82rem; padding: 0 10px; border: 1px solid var(--border); border-radius: 8px; background: var(--bg); color: var(--text); }
#collab-role-sel { width: auto; flex-shrink: 0; height: 100%; box-sizing: border-box; font-size: .82rem; padding: 0 8px; border: 1px solid var(--border); border-radius: 8px; background: var(--bg); color: var(--text); }
#collab-invite-row .btn { height: 100%; box-sizing: border-box; padding: 0 16px; font-size: .82rem; }

/* ── Phase 16 — Hard Features ────────────────────────────────────────────────── */


/* H3 — Folders / tags */
.tag-chip {
  display: inline-flex; align-items: center; gap: 3px;
  padding: 1px 7px; border-radius: 99px; font-size: .65rem; font-weight: 600;
  background: color-mix(in srgb, var(--primary) 12%, transparent);
  color: var(--primary); border: 1px solid color-mix(in srgb, var(--primary) 25%, transparent);
  cursor: pointer; transition: background .12s;
}
.tag-chip:hover { background: color-mix(in srgb, var(--primary) 22%, transparent); }
.session-item .tag-chip { font-size: .58rem; padding: 0 5px; }
/* (#tag-filter-bar styles removed — that element only existed inside the
   now-deleted legacy prompt-library modal.) */

/* K3 — Side-by-side compare */
#compare-modal {
  display: none; position: fixed; inset: 0; z-index: 3300;
  background: rgba(0,0,0,.6); align-items: stretch; justify-content: center; padding: 16px;
}
#compare-modal.open { display: flex; }
#compare-box {
  background: var(--surface); border-radius: 14px; width: 100%;
  max-width: 1200px; display: flex; flex-direction: column; overflow: hidden;
}
#compare-header {
  display: flex; align-items: center; padding: 12px 16px;
  border-bottom: 1px solid var(--border); gap: 12px;
}
#compare-header h3 { margin: 0; font-size: .9rem; flex: 1; }
#compare-panes { display: flex; flex: 1; overflow: hidden; }
.compare-pane {
  flex: 1; overflow-y: auto; padding: 16px;
  border-right: 1px solid var(--border);
}
.compare-pane:last-child { border-right: none; }
.compare-pane-header {
  font-size: .75rem; font-weight: 700; color: var(--muted);
  margin-bottom: 10px; padding-bottom: 6px; border-bottom: 1px solid var(--border);
}

/* Phase 51 — Multi-model compare (single prompt fan-out) */
#mc-modal {
  display: none; position: fixed; inset: 0; z-index: 3300;
  background: rgba(0,0,0,.6); align-items: stretch; justify-content: center; padding: 16px;
}
#mc-modal.open { display: flex; }
#mc-box {
  background: var(--surface); border-radius: 14px; width: 100%;
  max-width: 1300px; max-height: 100%; display: flex; flex-direction: column; overflow: hidden;
}
#mc-header {
  display: flex; align-items: center; padding: 12px 16px;
  border-bottom: 1px solid var(--border); gap: 12px;
}
#mc-header h3 { margin: 0; font-size: .9rem; }
#mc-config {
  display: flex; flex-direction: column; gap: 10px;
  padding: 12px 16px; border-bottom: 1px solid var(--border);
}
#mc-prompt {
  width: 100%; resize: vertical; min-height: 56px;
  padding: 8px 10px; border-radius: 8px; border: 1px solid var(--border);
  background: var(--bg); color: var(--text); font-family: inherit; font-size: .85rem;
}
#mc-models {
  display: flex; flex-wrap: wrap; gap: 8px; max-height: 110px; overflow-y: auto;
  padding: 8px; border: 1px solid var(--border); border-radius: 8px; background: var(--bg);
}
.mc-model-chk {
  display: flex; align-items: center; gap: 5px;
  font-size: .76rem; color: var(--text);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 99px; padding: 3px 10px 3px 6px; cursor: pointer;
}
#mc-actions { display: flex; justify-content: flex-end; gap: 8px; align-items: center; }
#mc-hint { font-size: .74rem; color: var(--muted); margin-right: auto; }
#mc-panes { display: flex; flex: 1; overflow: auto; gap: 0; }
.mc-pane {
  flex: 1; min-width: 260px; overflow-y: auto; padding: 14px;
  border-right: 1px solid var(--border);
}
.mc-pane:last-child { border-right: none; }
.mc-pane-header {
  display: flex; align-items: center; justify-content: space-between;
  font-size: .75rem; font-weight: 700; color: var(--muted);
  margin-bottom: 10px; padding-bottom: 6px; border-bottom: 1px solid var(--border);
}
.mc-pane-status { font-size: .7rem; color: var(--muted); font-weight: 600; }
.mc-pane-body { font-size: .85rem; line-height: 1.55; }

/* Phase 53 — Prompt library tabs */
.pl-tab { opacity: .6; }
.pl-tab.active { opacity: 1; background: var(--primary); color: #fff; border-color: var(--primary); }
.pl-item {
  display: flex; flex-direction: column; gap: 4px; padding: 10px;
  border: 1px solid var(--border); border-radius: 8px; margin-bottom: 8px; background: var(--bg);
}
.pl-item-title { font-weight: 600; font-size: .85rem; }
.pl-item-desc { font-size: .76rem; color: var(--muted); }
.pl-item-meta { font-size: .7rem; color: var(--muted); display: flex; gap: 8px; align-items: center; }
.pl-item-actions { display: flex; gap: 6px; margin-top: 4px; }

/* Phase 54 — Workflows */
.wf-step {
  display: flex; flex-direction: column; gap: 6px; padding: 10px;
  border: 1px solid var(--border); border-radius: 8px; margin-bottom: 8px; background: var(--bg);
}
.wf-step-header { display: flex; align-items: center; gap: 8px; }
.wf-step-header input[type="text"] { flex: 1; }
.wf-step textarea { resize: vertical; font-size: .82rem; }
.wf-item {
  display: flex; flex-direction: column; gap: 4px; padding: 10px;
  border: 1px solid var(--border); border-radius: 8px; margin-bottom: 8px; background: var(--bg);
}
.wf-item-title { font-weight: 600; font-size: .85rem; }
.wf-item-meta { font-size: .72rem; color: var(--muted); }
.wf-item-actions { display: flex; gap: 6px; margin-top: 4px; }
.wf-result { border-left: 3px solid var(--primary); padding: 6px 10px; margin-bottom: 8px; font-size: .8rem; }
.wf-result-title { font-weight: 600; margin-bottom: 4px; }
.wf-result-error { color: var(--danger, #e5484d); }

/* ═══════════════════════════════════════════════════════════════
   COMPACT MOBILE COMPOSER
   ═══════════════════════════════════════════════════════════════ */

/* "+" button — hidden by default everywhere, shown on mobile compact only */
#compact-more-btn {
  display: none;
  width: 38px; height: 38px;
  -webkit-box-align: center; -ms-flex-align: center; align-items: center;
  -webkit-box-pack: center; -ms-flex-pack: center; justify-content: center;
  background: var(--surface);
  border: 1.5px solid var(--border);
  border-radius: 10px;
  cursor: pointer; color: var(--text);
  -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0;
  transition: background .15s, border-color .15s, box-shadow .15s;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}
#compact-more-btn:active { background: var(--border); }

/* Mobile inline quick-action strip (📎 🌐 🖼) — sits left of the "+" button.
   Hidden on desktop; shown only in compact mode. */
.composer-quick-strip { display: none; }
.qs-btn {
  width: 34px; height: 38px; position: relative;
  -webkit-box-align: center; -ms-flex-align: center; align-items: center;
  -webkit-box-pack: center; -ms-flex-pack: center; justify-content: center;
  background: var(--surface); border: 1.5px solid var(--border);
  border-radius: 10px; cursor: pointer; color: var(--text);
  -webkit-flex-shrink: 0; -ms-flex-negative: 0; flex-shrink: 0;
  transition: background .15s, border-color .15s, color .15s;
  -webkit-tap-highlight-color: transparent; touch-action: manipulation;
}
.qs-btn:active { background: var(--border); }
.qs-btn.tool-active {
  color: var(--primary);
  background: color-mix(in srgb, var(--primary) 12%, transparent);
  border-color: color-mix(in srgb, var(--primary) 30%, transparent);
}
.qs-attach-count {
  position: absolute; top: -5px; right: -5px; min-width: 15px; height: 15px;
  padding: 0 3px; border-radius: 8px; background: var(--primary); color: #fff;
  font-size: .6rem; font-weight: 700; line-height: 15px; text-align: center;
  display: none;
}
/* Draw mode replaces the toolbar — hide the quick strip while drawing */
.composer-card.draw-mode .composer-quick-strip { display: none !important; }

/* ── Mobile single-line PILL composer (≤768px) ──────────────────────────
   One rounded pill row:  ( + )   Ask anything…   ( ➤ )
   The "+" lifts inside the pill (left) and opens the options sheet (model,
   web, draw, persona, tools); send sits inside on the right. The caret is
   vertically centered via line-height == box height; JS adds .ta-multi once
   the text wraps to restore normal multi-line spacing.
   Applies to every mode, including draw/video/audio — it used to exclude
   draw-mode specifically (:not(.draw-mode)), which left #compact-more-btn at
   its base display:none and dropped draw mode back to the untransformed
   desktop-style toolbar on mobile ("a different smartcomposer"). Video/audio
   were never excluded and always worked fine, so draw mode is now treated
   the same way — #draw-mode-bar is position:fixed on mobile regardless, so
   this row's display:contents lift doesn't affect it either way. */
@media (max-width: 768px) {
  /* Everything except the textarea, "+" and send lives behind the "+" sheet */
  .composer-card .composer-mobile-header { display: none !important; }
  .composer-card .composer-tool-group { display: none !important; }
  .composer-card .composer-tools-left { display: none !important; }
  .composer-card .composer-quick-strip { display: none !important; }
  .composer-card #mic-btn { display: none !important; }

  /* Pill row */
  .composer-card {
    -webkit-flex-direction: row; flex-direction: row !important;
    -webkit-flex-wrap: wrap; flex-wrap: wrap !important;
    -webkit-box-align: center; -ms-flex-align: center; align-items: center !important;
    gap: 6px;
    padding: 6px 6px 6px 8px !important;
    border-radius: 24px !important;
  }
  /* Lift the toolbar + its right cluster so "+" and send become direct flex
     children of the card and can be ordered around the textarea. */
  .composer-card .composer-toolbar,
  .composer-card .composer-tools-right {
    display: contents !important;
  }

  /* Textarea — middle, grows. Caret centered via line-height == box height. */
  .composer-card #chat-input {
    -webkit-order: 2; -ms-flex-order: 2; order: 2;
    -webkit-flex: 1 1 0%; -ms-flex: 1 1 0%; flex: 1 1 0% !important;
    width: auto !important;
    min-width: 0;
    line-height: 40px !important;
    height: 40px;
    min-height: 40px !important;
    max-height: 120px !important;
    padding: 0 4px !important;
    box-sizing: border-box !important;
  }
  .composer-card #chat-input.ta-multi {
    line-height: 1.5 !important;
    padding: 9px 4px !important;
  }

  /* "+" leading, inside the pill (borderless icon) */
  .composer-card #compact-more-btn {
    display: -webkit-inline-flex !important; display: inline-flex !important;
    -webkit-order: 1; -ms-flex-order: 1; order: 1;
    width: 40px; height: 40px; margin: 0 !important;
    -webkit-box-align: center; align-items: center;
    -webkit-box-pack: center; justify-content: center;
    background: transparent !important; border: none !important;
    border-radius: 50% !important; color: var(--text);
    -webkit-flex-shrink: 0; flex-shrink: 0; -webkit-tap-highlight-color: transparent;
    -webkit-align-self: center; -ms-flex-item-align: center; align-self: center !important;
  }
  .composer-card #compact-more-btn:active { background: var(--border) !important; }

  /* Send trailing, inside the pill — stay vertically centered as the textarea
     grows to multiple lines (align-self overrides any conflicting rule). */
  .composer-card .send-btn {
    -webkit-order: 3; -ms-flex-order: 3; order: 3;
    width: 40px !important; height: 40px !important; border-radius: 50% !important;
    -webkit-align-self: center; -ms-flex-item-align: center; align-self: center !important;
  }

  /* Preview panels wrap onto their own line under the pill */
  .composer-card #md-preview-panel,
  .composer-card #composer-code-preview {
    -webkit-order: 4; -ms-flex-order: 4; order: 4;
    -webkit-flex-basis: 100%; flex-basis: 100%; width: 100%;
  }
}

/* ── Mobile tool / options sheet ────────────────────────────────────── */
#mobile-tool-sheet-backdrop {
  display: none;
  position: fixed;
  top: 0; left: 0; right: 0; bottom: 0;
  background: rgba(0,0,0,.42);
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
  z-index: 799;
  opacity: 0;
  transition: opacity .3s ease;
}
#mobile-tool-sheet-backdrop.open { opacity: 1; }

#mobile-tool-sheet {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 800;
  background: var(--surface);
  border-top: 1px solid var(--border);
  border-radius: 20px 20px 0 0;
  box-shadow: 0 -8px 40px rgba(0,0,0,.18);
  padding-bottom: env(safe-area-inset-bottom, 0px);
  display: none;
  -webkit-overflow-scrolling: touch;
  /* animation handled by JS toggling class */
  -webkit-transform: translateY(100%);
  -ms-transform: translateY(100%);
  transform: translateY(100%);
  transition: -webkit-transform .3s cubic-bezier(.16,1,.3,1);
  transition: transform .3s cubic-bezier(.16,1,.3,1);
  transition: transform .3s cubic-bezier(.16,1,.3,1), -webkit-transform .3s cubic-bezier(.16,1,.3,1);
}
#mobile-tool-sheet.open {
  -webkit-transform: translateY(0);
  -ms-transform: translateY(0);
  transform: translateY(0);
}

/* Handle */
.mts-handle-row {
  display: -webkit-box; display: -ms-flexbox; display: flex;
  -webkit-box-pack: center; -ms-flex-pack: center; justify-content: center;
  padding: 10px 0 4px;
}
.mts-handle {
  width: 36px; height: 4px;
  background: var(--border); border-radius: 2px;
}

/* Sheet header */
.mts-header {
  display: -webkit-box; display: -ms-flexbox; display: flex;
  -webkit-box-align: center; -ms-flex-align: center; align-items: center;
  -webkit-box-pack: justify; -ms-flex-pack: justify; justify-content: space-between;
  padding: 2px 16px 10px;
}
.mts-title {
  font-size: .88rem; font-weight: 700; color: var(--text); letter-spacing: -.01em;
  display: flex; align-items: center; gap: 6px;
}
.mts-title-icon { flex-shrink: 0; }
.mts-close {
  width: 28px; height: 28px;
  display: -webkit-box; display: -ms-flexbox; display: flex;
  -webkit-box-align: center; -ms-flex-align: center; align-items: center;
  -webkit-box-pack: center; -ms-flex-pack: center; justify-content: center;
  background: var(--bg); border: 1px solid var(--border); border-radius: 8px;
  cursor: pointer; color: var(--muted);
  -webkit-tap-highlight-color: transparent;
  transition: background .15s;
}
.mts-close:active { background: var(--border); }

/* Body */
.mts-body { padding: 0 14px 18px; overflow-y: auto; max-height: 60vh; }
.mts-section { margin-bottom: 14px; }
.mts-label {
  font-size: .68rem; font-weight: 700; color: var(--muted);
  text-transform: uppercase; letter-spacing: .07em; margin-bottom: 7px;
}

/* Model selector */
.mts-model-wrap { position: relative; }
.mts-model-wrap::after {
  content: '';
  position: absolute; right: 12px; top: 50%;
  -webkit-transform: translateY(-60%) rotate(45deg);
  -ms-transform: translateY(-60%) rotate(45deg);
  transform: translateY(-60%) rotate(45deg);
  width: 6px; height: 6px;
  border-right: 2px solid var(--muted); border-bottom: 2px solid var(--muted);
  pointer-events: none;
}
.mts-model-select {
  width: 100%; padding: 10px 32px 10px 12px;
  border: 1.5px solid var(--border); border-radius: 10px;
  background: var(--bg); color: var(--text);
  font-size: .88rem; font-family: inherit;
  outline: none; cursor: pointer;
  -webkit-appearance: none; -moz-appearance: none; appearance: none;
}
.mts-model-select:focus { border-color: var(--primary); }
.mts-model-wrap { position: relative; }
.mts-model-trigger {
  width: 100%; padding: 10px 12px;
  border: 1.5px solid var(--border); border-radius: 10px;
  background: var(--bg); color: var(--text);
  font-size: .88rem; text-align: left;
}
.mts-model-trigger .composer-model-label {
  max-width: none; color: var(--text); font-weight: 500; font-size: .88rem;
}

/* Action buttons — horizontally scrollable strip on mobile: with 7 possible
   buttons (Attach/Reason/Web/Draw/Video/Audio/Voice), flex:1 items on a
   narrow screen hit their content min-width and overflow the sheet with no
   way to reach the clipped ones. Fixed-width items + overflow-x:auto turns
   that into a deliberate swipeable row instead — same pattern already used
   for .composer-tools-left on mobile. No longer bleeds past .mts-body's
   14px padding (a negative-margin/re-pad trick used to do that) — it drifted
   the row's start out from under the "Tools" label above it, so this now
   just sits inside the same 14px inset as every other section. */
.mts-actions {
  display: -webkit-box; display: -ms-flexbox; display: flex;
  gap: 8px;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  flex-wrap: nowrap;
  scroll-snap-type: x proximity;
  margin: 0;
  padding: 2px 0 6px;
  scrollbar-width: none; -ms-overflow-style: none;
}
.mts-actions::-webkit-scrollbar { display: none; }
/* Applied via JS (_syncMtsActionsAlign) only when every button already fits
   without scrolling — centers the row instead of leaving it packed to the
   left. Left as the default/unset state whenever it overflows, since
   centering an overflowing flex row clips content behind both edges. */
.mts-actions.mts-actions-fit { justify-content: center; }
.mts-action-btn {
  display: -webkit-box; display: -ms-flexbox; display: flex;
  -webkit-box-orient: vertical; -webkit-box-direction: normal;
  -ms-flex-direction: column; flex-direction: column;
  -webkit-box-align: center; -ms-flex-align: center; align-items: center;
  -webkit-box-pack: center; -ms-flex-pack: center; justify-content: center;
  gap: 5px;
  -webkit-box-flex: 0; -ms-flex: 0 0 68px; flex: 0 0 68px;
  scroll-snap-align: start;
  padding: 10px 6px;
  background: var(--bg); border: 1px solid var(--border); border-radius: 10px;
  cursor: pointer; color: var(--text);
  font-size: .72rem; font-weight: 600; font-family: inherit;
  -webkit-tap-highlight-color: transparent;
  transition: background .15s, border-color .15s, color .15s;
}
.mts-action-btn:active { background: var(--border); }
.mts-action-btn.mts-active,
.mts-action-btn.tool-active {
  background: rgba(37,99,235,.08);
  border-color: rgba(37,99,235,.25); color: var(--primary);
}
.mts-action-btn svg { color: var(--muted); }
.mts-action-btn.mts-active svg,
.mts-action-btn.tool-active svg { color: var(--primary); }

/* Temperature */
.mts-temp-row {
  display: -webkit-box; display: -ms-flexbox; display: flex;
  -webkit-box-align: center; -ms-flex-align: center; align-items: center;
  gap: 10px; padding: 10px 12px;
  background: var(--bg); border: 1px solid var(--border); border-radius: 10px;
}
.mts-temp-row input[type=range] {
  -webkit-appearance: none;
  -webkit-box-flex: 1; -ms-flex: 1; flex: 1;
  height: 4px; border-radius: 2px;
  background: var(--border); outline: none; cursor: pointer;
}
.mts-temp-row input[type=range]::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 20px; height: 20px;
  border-radius: 50%; background: var(--primary); cursor: pointer;
  box-shadow: 0 1px 4px rgba(0,0,0,.2);
}
.mts-temp-row input[type=range]::-moz-range-thumb {
  width: 20px; height: 20px;
  border-radius: 50%; background: var(--primary);
  border: none; cursor: pointer;
}
.mts-temp-val {
  font-size: .82rem; font-weight: 700; color: var(--primary);
  min-width: 28px; text-align: center; font-variant-numeric: tabular-nums;
}

/* Divider */
.mts-divider { height: 1px; background: var(--border); margin: 12px 0; }

/* Full-compose toggle button */
.mts-mode-toggle {
  width: 100%;
  display: -webkit-box; display: -ms-flexbox; display: flex;
  -webkit-box-align: center; -ms-flex-align: center; align-items: center;
  -webkit-box-pack: center; -ms-flex-pack: center; justify-content: center;
  gap: 8px; padding: 11px;
  background: none; border: 1.5px solid var(--border); border-radius: 10px;
  font-size: .82rem; font-weight: 600; font-family: inherit;
  cursor: pointer; color: var(--text);
  -webkit-tap-highlight-color: transparent;
  transition: border-color .15s, background .15s;
}
.mts-mode-toggle:active { background: var(--border); }
.mts-mode-toggle.mts-full-active {
  background: rgba(37,99,235,.07);
  border-color: rgba(37,99,235,.3); color: var(--primary);
}

/* ── AI Image Generation bubble ──────────────────────────────────────────── */
.msg-image-bubble {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 0;
}
.msg-image-bubble img.gen-image {
  max-width: min(480px, 100%);
  border-radius: 12px;
  border: 1.5px solid var(--border);
  display: block;
  cursor: zoom-in;
  transition: box-shadow .2s, transform .15s;
  background: var(--border);   /* placeholder while loading */
  /* Reserve a square footprint before the file loads (most AI image models
     default to 1024x1024) — an inline style="aspect-ratio:W/H" set from a
     known real size, if ever provided, overrides this. Without any
     reservation the browser collapses the <img> to ~0 height until it
     decodes, which is what made scrollHeight (and the visible scrollbar
     thumb) jump every time an image message scrolled into view.
     The "auto" prefix is required: plain "1" forces every image into a
     square box forever (per spec, a bare <ratio> wins over the element's
     own intrinsic size), squashing non-square generations (e.g. 1024x1792
     portrait or 1792x1024 landscape). "auto 1" only falls back to the 1:1
     placeholder while there's no intrinsic size yet (nothing decoded) and
     switches to the real image's natural ratio the instant it loads. */
  aspect-ratio: auto 1 / 1;
}
.msg-image-bubble img.gen-image:hover {
  box-shadow: 0 4px 20px rgba(0,0,0,.18);
  transform: translateY(-1px);
}
.msg-image-prompt {
  font-size: .78rem;
  color: var(--muted);
  font-style: italic;
  max-width: min(480px, 100%);
  line-height: 1.4;
}
.msg-image-actions {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
}
.img-action-btn {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 10px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 7px;
  font-size: .74rem;
  font-weight: 600;
  color: var(--muted);
  cursor: pointer;
  font-family: inherit;
  transition: background .15s, color .15s, border-color .15s;
  text-decoration: none;
}
.img-action-btn:hover {
  background: color-mix(in srgb, var(--primary) 10%, transparent);
  color: var(--primary);
  border-color: color-mix(in srgb, var(--primary) 30%, transparent);
}
.gen-media-error {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 14px 16px;
  max-width: min(480px, 100%);
  background: var(--surface);
  border: 1.5px dashed var(--border);
  border-radius: 12px;
  color: var(--muted);
  font-size: .82rem;
}
.gen-media-error svg { flex-shrink: 0; opacity: .7; }

/* AI-generated downloadable file card — fills the bubble width like a table/code block */
.gen-file-card,
.gen-file-card-v2 {
  display: flex; flex-direction: column;
  width: 100%; max-width: 100%;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  margin: 10px 0; overflow: hidden;
  box-shadow: 0 1px 3px rgba(0,0,0,.05);
  transition: border-color .15s, box-shadow .15s;
}
.gen-file-card-v2:hover {
  border-color: color-mix(in srgb, var(--primary) 30%, var(--border));
  box-shadow: 0 3px 14px rgba(0,0,0,.08);
}
.gfc-header {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 14px;
  background: color-mix(in srgb, var(--primary) 4%, var(--surface));
}
.gfc-actions { display: flex; gap: 8px; margin-left: auto; flex-shrink: 0; }
.gfc-btn {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 0 12px; height: 32px; border-radius: 8px;
  border: 1px solid var(--border); background: var(--bg);
  color: var(--muted); font-size: .76rem; font-weight: 600;
  cursor: pointer; font-family: inherit; text-decoration: none;
  transition: all .15s; white-space: nowrap;
}
.gfc-btn:hover {
  background: color-mix(in srgb, var(--primary) 10%, transparent);
  color: var(--primary);
  border-color: color-mix(in srgb, var(--primary) 35%, transparent);
  transform: translateY(-1px);
}
.gfc-btn.gen-file-download {
  background: var(--primary);
  border-color: var(--primary);
  color: #fff;
}
.gfc-btn.gen-file-download:hover {
  background: color-mix(in srgb, var(--primary) 85%, #000);
  border-color: color-mix(in srgb, var(--primary) 85%, #000);
  color: #fff;
}
/* Snippet area */
.gfc-snippet {
  border-top: 1px solid var(--border);
  background: var(--bg);
  max-height: 240px; overflow: hidden;
  position: relative;
}
.gfc-snippet::after {
  content: ''; position: absolute; bottom: 0; left: 0; right: 0;
  height: 40px;
  background: linear-gradient(transparent, var(--bg));
  pointer-events: none;
}
.gfc-snip-loading {
  display: block; padding: 12px 14px;
  font-size: .74rem; color: var(--muted); font-style: italic;
}
.gfc-text-snip, .gfc-code-snip {
  margin: 0; padding: 12px 14px;
  font-family: 'Fira Code','Consolas',monospace;
  font-size: .78rem; line-height: 1.6;
  color: var(--text); white-space: pre; overflow-x: auto;
  tab-size: 2;
}
/* app.css's `.msg-bubble pre` fallback forces a hardcoded dark code-block
   background (#1e1e2e) onto every <pre> in a bubble. That's correct for
   .gfc-code-snip (real code — its color comes from that same fallback's
   `.msg-bubble pre code`, #cdd6f4, which reads fine against #1e1e2e). But
   .gfc-text-snip previews a plain TEXT file, not code: it inherited that
   forced dark background while its own color stays theme-based (var(--text),
   a dark navy in light mode) — dark-on-dark, unreadable. Restore the
   theme-aware background the parent .gfc-snippet already sets so the two
   stay in sync in every theme. */
.msg-bubble pre.gfc-text-snip { background: transparent; }
.gfc-code-snip code { font: inherit; background: none; padding: 0; }
.gfc-snip-more {
  padding: 5px 14px 10px;
  font-size: .72rem; color: var(--muted); font-style: italic;
}
/* CSV mini-table */
.gfc-csv-table {
  width: 100%; border-collapse: collapse;
  font-size: .78rem; font-family: inherit;
}
.gfc-csv-table th {
  padding: 6px 12px; text-align: left;
  font-weight: 700; font-size: .68rem;
  text-transform: uppercase; letter-spacing: .05em;
  color: var(--muted); border-bottom: 1.5px solid var(--border);
  background: var(--surface); white-space: nowrap;
}
.gfc-csv-table td {
  padding: 6px 12px; color: var(--text);
  border-bottom: 1px solid var(--border);
  white-space: nowrap; max-width: 220px;
  overflow: hidden; text-overflow: ellipsis;
}
.gfc-csv-table tr:last-child td { border-bottom: none; }
.gen-file-icon {
  flex-shrink: 0;
  width: 42px;
  height: 42px;
  border-radius: 10px;
  background: color-mix(in srgb, var(--primary) 14%, transparent);
  color: var(--primary);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: .68rem;
  font-weight: 800;
  letter-spacing: .02em;
}
.gen-file-info { flex: 1; min-width: 0; }
.gen-file-name {
  font-size: .88rem;
  font-weight: 600;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.gen-file-size {
  font-size: .74rem;
  color: var(--muted);
  margin-top: 2px;
}

/* ── File Preview Modal ───────────────────────────────────────────────────── */
#file-preview-modal {
  display: none; position: fixed; inset: 0; z-index: 4000;
  background: rgba(0,0,0,.55); align-items: center; justify-content: center;
}
#file-preview-modal.open { display: flex; }
#file-preview-box {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 14px; width: min(940px, 96vw); height: min(86vh, 820px);
  display: flex; flex-direction: column; overflow: hidden;
  box-shadow: 0 24px 80px rgba(0,0,0,.35);
  position: relative;
}
#fp-header {
  display: flex; align-items: center; gap: 8px; padding: 10px 14px;
  border-bottom: 1px solid var(--border); flex-shrink: 0; flex-wrap: wrap;
}
#fp-title-group {
  display: flex; align-items: center; gap: 9px; flex: 1; min-width: 0;
}
#fp-icon {
  flex-shrink: 0; width: 34px; height: 34px; border-radius: 8px;
  background: color-mix(in srgb, var(--primary) 13%, transparent);
  color: var(--primary); display: flex; align-items: center; justify-content: center;
  font-size: .62rem; font-weight: 800; letter-spacing: .02em;
}
#fp-filename {
  font-size: .85rem; font-weight: 600; color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0;
}
#fp-filesize { font-size: .7rem; color: var(--muted); margin-top: 1px; }
#fp-header-tools {
  display: flex; align-items: center; gap: 4px; flex-shrink: 0; flex-wrap: nowrap;
}
/* Close button — same square .fp-action-btn look as the rest of the toolbar.
   Lives inline in the tools row on desktop (unchanged from before); only the
   mobile media query below pins it to the box corner and hides the row's
   scrolling copy, since desktop never had the clipping problem. */
#fp-close-btn { flex-shrink: 0; }
#fp-view-toggles { display: flex; gap: 3px; }
.fp-view-btn {
  padding: 3px 9px; border-radius: 6px; border: 1px solid var(--border);
  background: var(--bg); color: var(--muted); font-size: .72rem; font-weight: 600;
  cursor: pointer; font-family: inherit; transition: all .15s; white-space: nowrap;
}
.fp-view-btn.active { background: var(--primary); color: #fff; border-color: var(--primary); }
.fp-view-btn:hover:not(.active) { color: var(--text); }
.fp-tool-sep { width: 1px; height: 18px; background: var(--border); margin: 0 3px; flex-shrink: 0; }
.fp-action-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; border-radius: 6px; border: 1px solid var(--border);
  background: transparent; color: var(--muted); cursor: pointer;
  transition: all .15s; flex-shrink: 0; font-family: inherit;
}
.fp-action-btn:hover { color: var(--text); background: var(--bg); }
.fp-action-btn.active { color: var(--primary); border-color: var(--primary); background: color-mix(in srgb,var(--primary) 10%,transparent); }
.fp-font-btn {
  width: auto; padding: 0 7px; font-weight: 700;
}
#fp-responsive-bar {
  display: none; padding: 5px 14px; border-bottom: 1px solid var(--border);
  flex-shrink: 0; align-items: center; gap: 6px;
}
#fp-responsive-bar.visible { display: flex; }
.fp-resp-btn {
  padding: 3px 10px; border-radius: 6px; border: 1px solid var(--border);
  background: var(--bg); color: var(--muted); font-size: .72rem; cursor: pointer;
  font-family: inherit; transition: all .15s;
}
.fp-resp-btn.active { background: var(--primary); color: #fff; border-color: var(--primary); }
#fp-search-bar {
  display: none; padding: 5px 14px; border-bottom: 1px solid var(--border);
  flex-shrink: 0; align-items: center; gap: 6px;
}
#fp-search-bar.visible { display: flex; }
#fp-search-input {
  flex: 1; padding: 4px 9px; border: 1px solid var(--border); border-radius: 6px;
  background: var(--bg); color: var(--text); font-size: .8rem; font-family: inherit; outline: none;
}
#fp-search-count { font-size: .74rem; color: var(--muted); white-space: nowrap; }
#fp-content { flex: 1; overflow: auto; position: relative; }
#fp-spinner {
  width: 28px; height: 28px; border: 3px solid var(--border);
  border-top-color: var(--primary); border-radius: 50%;
  animation: fpSpin .7s linear infinite; margin: auto;
}
@keyframes fpSpin { to { transform: rotate(360deg); } }
.fp-error {
  padding: 28px; text-align: center; color: var(--muted); font-size: .85rem; line-height: 1.7;
}
.fp-error a { color: var(--primary); }
#fp-pre-wrap { margin: 0; height: 100%; box-sizing: border-box; overflow: auto; }
#fp-pre-wrap pre {
  margin: 0; padding: 14px 16px; font-size: 13px;
  font-family: 'Fira Code','Consolas',monospace;
  color: var(--text); background: transparent; white-space: pre;
  min-height: 100%; tab-size: 4; line-height: 1.65;
}
#fp-pre-wrap.fp-soft-wrap pre { white-space: pre-wrap !important; word-break: break-word !important; overflow-x: hidden !important; }
.fp-line-num {
  display: inline-block; min-width: 3em; margin-right: 14px;
  color: var(--muted); user-select: none; text-align: right;
  opacity: .45; font-size: .85em; pointer-events: none;
}
#fp-md-content { padding: 18px 22px; font-size: .9rem; line-height: 1.75; color: var(--text); }
#fp-table-wrap { overflow: auto; height: 100%; box-sizing: border-box; }
#fp-table-wrap table { border-collapse: collapse; font-size: .79rem; min-width: 100%; }
#fp-table-wrap th {
  position: sticky; top: 0; background: var(--surface);
  padding: 8px 11px; border: 1px solid var(--border);
  font-weight: 700; color: var(--text); text-align: left;
  cursor: pointer; user-select: none; white-space: nowrap; z-index: 1;
}
#fp-table-wrap th:hover { background: var(--bg); }
.fp-sort-icon { margin-left: 5px; opacity: .35; font-style: normal; }
.sort-asc .fp-sort-icon::after { content: '↑'; opacity: 1; }
.sort-desc .fp-sort-icon::after { content: '↓'; opacity: 1; }
#fp-table-wrap td {
  padding: 5px 11px; border: 1px solid var(--border); color: var(--text);
  max-width: 280px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
#fp-table-wrap tr:nth-child(even) td { background: color-mix(in srgb,var(--primary) 3%,var(--bg)); }
#fp-table-wrap td:hover { white-space: normal; cursor: default; }
#fp-json-wrap {
  padding: 14px 16px; font-family: 'Fira Code','Consolas',monospace; font-size: .82rem;
  line-height: 1.7; color: var(--text);
}
.fp-json-node { line-height: 1.75; }
.fp-json-toggle { cursor: pointer; user-select: none; color: var(--muted); font-size: .8em; margin-right: 3px; }
.fp-json-key { color: #7dd3fc; }
[data-theme="light"] .fp-json-key { color: #2563eb; }
.fp-json-str { color: #86efac; }
[data-theme="light"] .fp-json-str { color: #16a34a; }
.fp-json-num { color: #fdba74; }
[data-theme="light"] .fp-json-num { color: #c2410c; }
.fp-json-bool { color: #c084fc; }
[data-theme="light"] .fp-json-bool { color: #7c3aed; }
.fp-json-null { color: var(--muted); font-style: italic; }
.fp-json-collapsed .fp-json-children { display: none; }
.fp-json-count { color: var(--muted); font-size: .76em; margin-left: 5px; font-family: inherit; }
#fp-iframe-wrap { height: 100%; display: flex; justify-content: center; background: var(--bg); box-sizing: border-box; }
#fp-iframe { border: none; height: 100%; background: #fff; display: block; }
#fp-editor-wrap { height: 100%; display: flex; flex-direction: column; }
#fp-editor {
  flex: 1; width: 100%; box-sizing: border-box; border: none; resize: none;
  padding: 14px 16px; font-size: 13px; font-family: 'Fira Code','Consolas',monospace;
  background: var(--bg); color: var(--text); line-height: 1.65; outline: none;
}
.fp-editor-bar {
  padding: 7px 12px; border-top: 1px solid var(--border); display: flex;
  gap: 8px; align-items: center; background: var(--surface); flex-shrink: 0;
}
#fp-footer {
  display: flex; align-items: center; justify-content: space-between;
  padding: 6px 14px; border-top: 1px solid var(--border); flex-shrink: 0;
  font-size: .72rem; color: var(--muted); gap: 8px;
}
#fp-stats { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#fp-nav { display: flex; align-items: center; gap: 6px; flex-shrink: 0; }
.fp-nav-btn {
  padding: 2px 8px; border: 1px solid var(--border); border-radius: 5px;
  background: var(--bg); color: var(--muted); font-size: .72rem; cursor: pointer;
  font-family: inherit; transition: color .15s;
}
.fp-nav-btn:hover:not(:disabled) { color: var(--text); }
.fp-nav-btn:disabled { opacity: .35; cursor: default; }
#fp-nav-label { color: var(--text); font-weight: 600; white-space: nowrap; }
.fp-highlight { background: #fef08a; color: #713f12; border-radius: 2px; }
[data-theme="dark"] .fp-highlight { background: #854d0e; color: #fef08a; }

/* Image generation modal loading spinner */
@keyframes imgGenSpin { to { transform: rotate(360deg); } }
.img-gen-spinner {
  width: 16px; height: 16px;
  border: 2.5px solid rgba(255,255,255,.35);
  border-top-color: #fff;
  border-radius: 50%;
  animation: imgGenSpin .7s linear infinite;
  display: inline-block;
  flex-shrink: 0;
}

/* Video generation — placeholder bubble while polling */
.msg-video-bubble{padding:12px}
.video-gen-status{display:flex;align-items:center;gap:9px;color:var(--muted);font-size:.85rem}
.video-gen-status .img-gen-spinner{border-color:color-mix(in srgb,var(--primary) 30%,transparent);border-top-color:var(--primary)}
.video-gen-error{color:#dc2626}
/* aspect-ratio reserves the box before metadata loads (readyState 0) — same
   "collapses to ~0 height, snaps in on load" issue as .gen-image, just for
   video. Generated video is landscape in practice, so 16:9 is a close-enough
   guess; the "auto" prefix makes the element switch to its real intrinsic
   ratio once metadata arrives instead of permanently forcing 16:9 on
   portrait/square video, same mechanism as documented on .msg-bubble img
   above. */
.gen-video{display:block;background:#000;aspect-ratio:auto 16 / 9}

/* Image lightbox */
#img-lightbox {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 9000;
  background: rgba(0,0,0,.88);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  align-items: center;
  justify-content: center;
  cursor: zoom-out;
}
#img-lightbox.open { display: flex; }
#img-lightbox img {
  max-width: 92vw;
  max-height: 90vh;
  border-radius: 10px;
  box-shadow: 0 8px 48px rgba(0,0,0,.5);
  cursor: default;
}
#img-lightbox-close {
  position: absolute;
  top: 16px; right: 16px;
  background: rgba(255,255,255,.15);
  border: none; border-radius: 50%;
  width: 36px; height: 36px;
  color: #fff; font-size: 18px;
  cursor: pointer; display: flex;
  align-items: center; justify-content: center;
  transition: background .15s;
}
#img-lightbox-close:hover { background: rgba(255,255,255,.28); }

/* Image edit / inpainting modal */
#img-edit-modal {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 9100;
  background: rgba(0,0,0,.6);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
  align-items: center;
  justify-content: center;
  padding: 16px;
}
#img-edit-modal.open { display: flex; }
.img-edit-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  width: min(640px, 100%);
  max-height: 92vh;
  overflow: auto;
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.img-edit-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.img-edit-header h3 { margin: 0; font-size: 1rem; }
.img-edit-canvas-wrap {
  position: relative;
  max-width: 100%;
  align-self: center;
  border-radius: 10px;
  overflow: hidden;
  border: 1.5px solid var(--border);
  background: repeating-conic-gradient(#80808022 0% 25%, transparent 0% 50%) 50% / 16px 16px;
}
.img-edit-canvas-wrap canvas {
  display: block;
  max-width: 100%;
  touch-action: none;
}
.img-edit-canvas-wrap canvas.img-edit-mask {
  position: absolute;
  top: 0; left: 0;
  opacity: .45;
  cursor: crosshair;
}
.img-edit-tools {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  font-size: .8rem;
  color: var(--muted);
}
.img-edit-tools label { display: flex; align-items: center; gap: 6px; }
.img-edit-tools input[type="range"] { width: 100px; }
.img-edit-hint {
  font-size: .74rem;
  color: var(--muted);
  line-height: 1.4;
}
#img-edit-prompt {
  width: 100%;
  resize: vertical;
  min-height: 60px;
  padding: 8px 10px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--bg);
  color: var(--text);
  font-family: inherit;
  font-size: .85rem;
}
.img-edit-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  flex-wrap: wrap;
}
.img-edit-error {
  font-size: .78rem;
  color: var(--danger, #e5484d);
  display: none;
}

/* ── Docgen streaming placeholder — shown while a ```docgen:/```file: block
   is still streaming, in place of the raw JSON/HTML spec. Token-based (var(
   --surface)/var(--border)/var(--muted)/var(--primary)) so it already
   follows light/dark/oled mode and all 14 accent themes automatically —
   the accent shows up in the spinner and the indeterminate progress bar. ── */
.gf-building-placeholder {
  display: block;
  max-width: 340px;
  margin-top: 8px;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--surface);
  font-size: .85rem;
}
.gfb-row { display: flex; align-items: center; gap: 9px; }
.gfb-label { color: var(--text); font-weight: 500; }
.gfb-progress {
  margin-top: 10px;
  height: 4px;
  border-radius: 2px;
  background: var(--border);
  overflow: hidden;
}
.gfb-progress-bar {
  height: 100%;
  width: 40%;
  border-radius: 2px;
  background: var(--primary);
  animation: gfb-indeterminate 1.4s ease-in-out infinite;
}
@keyframes gfb-indeterminate {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(350%); }
}
.gf-building-spinner {
  width: 13px;
  height: 13px;
  border: 2px solid var(--border);
  border-top-color: var(--primary);
  border-radius: 50%;
  animation: spin .7s linear infinite;
  flex-shrink: 0;
}
.img-edit-error.visible { display: block; }

/* ── Streaming code-fence preloader — shown while an ordinary ```lang block
   is still streaming (the closing ``` hasn't arrived yet), in place of the
   raw un-highlighted partial text/backticks. Shaped like the real
   .code-block-wrap it will become, but token-based (var(--surface)/var(
   --border)/var(--muted)/var(--primary)) rather than that block's fixed
   dark editor palette, so the placeholder itself follows the page's
   light/dark/oled mode and active accent theme like every other UI
   surface — .code-block-wrap.code-gen-placeholder overrides the base
   block's hardcoded background/border for exactly this element. ────────── */
.code-block-wrap.code-gen-placeholder {
  background: var(--surface);
  border-color: var(--border);
}
.code-gen-placeholder .code-header {
  gap: 8px;
  background: color-mix(in srgb, var(--border) 30%, var(--surface));
  border-bottom-color: var(--border);
}
.code-gen-placeholder .code-lang {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  text-transform: none;
  color: var(--muted);
}
.code-gen-placeholder .gf-building-spinner { border-color: var(--border); border-top-color: var(--primary); }
.code-gen-skeleton { padding: 14px 16px; display: flex; flex-direction: column; gap: 9px; }
.cgs-line {
  height: 10px;
  border-radius: 5px;
  background: linear-gradient(90deg, var(--border) 25%, color-mix(in srgb, var(--border) 45%, var(--surface)) 50%, var(--border) 75%);
  background-size: 200% 100%;
  animation: cgs-shimmer 1.3s ease-in-out infinite;
}
@keyframes cgs-shimmer {
  0%   { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   2026 REDESIGN — modern glass/gradient reskin (token-based, appended last so
   these override earlier equal-specificity rules by cascade order).
   Every color comes from tokens.css so all 14 accent themes × light/dark/oled
   keep working automatically.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Slim guest welcome ─────────────────────────────────────────────────── */
#guest-welcome { display: flex; align-items: center; justify-content: center; min-height: 100%; padding: 24px; }
.gw-slim {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  gap: 14px; max-width: 560px; margin: 0 auto; padding: 40px 28px;
  background: var(--surface-glass);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  border: 1px solid var(--border-glass); border-radius: var(--r-xl);
  box-shadow: var(--shadow-3);
}
.gw-slim-title { font-size: var(--fs-xl); font-weight: 800; letter-spacing: -.02em; color: var(--text-strong); margin: 0; }
.gw-slim-tagline {
  font-size: var(--fs-base); font-weight: var(--fw-semibold); margin: -6px 0 0;
  background: var(--grad-text);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
}
.gw-slim-chips { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; }
.gw-slim-chip {
  font-family: inherit; font-size: var(--fs-xs); font-weight: var(--fw-medium);
  color: var(--text); background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-full); padding: 8px 14px; cursor: pointer;
  transition: border-color var(--t-fast) ease, color var(--t-fast) ease,
              background-color var(--t-fast) ease, transform var(--t-fast) var(--ease-out);
}
.gw-slim-chip:hover { border-color: var(--primary); color: var(--primary); background: var(--accent-softer); transform: translateY(-1px); }
.gw-slim-links { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; margin-top: 4px; }

/* ── Sidebar polish ─────────────────────────────────────────────────────── */
#new-chat-btn {
  background: var(--grad-brand); color: var(--on-accent);
  border: none; border-radius: var(--r-sm);
  box-shadow: var(--shadow-accent);
  transition: filter var(--t-fast) ease, transform var(--t-fast) var(--ease-out);
}
#new-chat-btn:hover { filter: brightness(1.06); transform: translateY(-1px); }
#new-chat-btn:active { transform: scale(.98); }

.session-item { border-radius: var(--r-sm); transition: background-color var(--t-fast) ease; }
.session-item:hover { background: var(--accent-softer); }
.session-item.active {
  background: var(--accent-soft);
}
.session-item.active .session-title { color: var(--primary); font-weight: var(--fw-semibold); }

/* Session-list date group headers (rendered by dashboard.js) */
.session-group-label {
  position: sticky; top: 0; z-index: 1;
  font-size: .68rem; font-weight: var(--fw-bold); text-transform: uppercase;
  letter-spacing: .08em; color: var(--muted-2);
  padding: 10px 12px 4px;
  background: linear-gradient(var(--surface-glass) 75%, transparent);
  pointer-events: none;
}
/* ── Message bubbles ────────────────────────────────────────────────────── */
.msg-user .msg-bubble {
  background: var(--grad-brand);
  color: var(--on-accent);
  border: none;
  border-radius: var(--r-lg);
  border-top-right-radius: var(--r-xs);
  box-shadow: var(--shadow-1);
}
.msg-user .msg-bubble a { color: var(--on-accent); text-decoration: underline; }
.msg-ai .msg-bubble {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  border-top-left-radius: var(--r-xs);
  box-shadow: var(--shadow-1);
}

/* ── Composer polish ────────────────────────────────────────────────────── */
.composer-card {
  border-radius: var(--r-lg);
  transition: box-shadow var(--t-base) ease, border-color var(--t-base) ease;
}
.composer-card:focus-within {
  border-color: color-mix(in srgb, var(--primary) 55%, var(--border-strong));
  box-shadow: 0 0 10px 0 var(--accent-ring);
}
.send-btn {
  background: var(--grad-brand);
  border-radius: 50%;
}
.send-btn:hover { background: var(--grad-brand); filter: brightness(1.08); }

/* ── Themed thin scrollbars on the main scroll surfaces ─────────────────── */
.chat-messages, .session-list, .app-sidebar {
  scrollbar-width: thin; scrollbar-color: var(--accent-ring) transparent;
}
.chat-messages::-webkit-scrollbar, .session-list::-webkit-scrollbar { width: 8px; }
.chat-messages::-webkit-scrollbar-track, .session-list::-webkit-scrollbar-track { background: transparent; }
.chat-messages::-webkit-scrollbar-thumb, .session-list::-webkit-scrollbar-thumb {
  background: var(--accent-ring); border-radius: var(--r-full);
}
.chat-messages::-webkit-scrollbar-thumb:hover, .session-list::-webkit-scrollbar-thumb:hover { background: var(--primary); }

/* ── Welcome screen (logged-in) polish ──────────────────────────────────── */
/* Same exact gradient as the logo tile / buttons (--grad-brand) — guarantees
   this text always matches that hue and lightness, in every theme, with no
   separate light/dark overrides to keep in sync. */
.welcome-screen h2 {
  background: var(--grad-brand);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
}
.welcome-chips .chip, .chip {
  transition: border-color var(--t-fast) ease, color var(--t-fast) ease,
              background-color var(--t-fast) ease, transform var(--t-fast) var(--ease-out);
}
.chip:hover { transform: translateY(-1px); }

/* ── Reduced motion ─────────────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  #new-chat-btn, .gw-slim-chip, .chip, .composer-card, .session-item { transition: none; }
  #new-chat-btn:hover, .gw-slim-chip:hover, .chip:hover { transform: none; }
}
