/* ============================================================
   bookware.css — design-system finishing layer
   Loaded last. base.css re-points the tokens; this file settles the
   things tokens can't reach: brand type, the leftover neon decoration,
   and the shared shapes of buttons, fields, panels and chips.
   ============================================================ */

/* ============================================================
   GROUND
   Bootstrap loads after every ARIA stylesheet and repaints `body` with
   its own white background and font stack. Restated here, after it.
   ============================================================ */
body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body, var(--font-sans));
  font-size: 0.875rem;
  line-height: 1.5;
  letter-spacing: var(--text-spacing, 0);
  cursor: var(--cursor-style, default);
  -webkit-font-smoothing: antialiased;
}

/* Bootstrap also owns bare `button` and the form controls. */
.btn,
button {
  font-family: inherit;
}

/* ============================================================
   ICONS
   Bootstrap Icons, the set BookWare uses. They are a font, so they
   inherit colour from the element and scale with its font-size — the
   emoji they replaced did neither, which is why the old sidebar was a
   row of multicoloured glyphs against monochrome labels.
   ============================================================ */
.bi {
  /* The font ships a small baseline offset that leaves icons sitting low
     next to text. -0.125em is Bootstrap's own correction. */
  vertical-align: -0.125em;
  line-height: 1;
  flex-shrink: 0;
}

/* Slightly smaller than the label they sit beside, so the text leads. */
.homeLabel .bi,
.settingsTab .bi,
.secondaryBtn .bi,
.voiceBtn .bi,
.hwToolBtn .bi,
.toolDropItem .bi {
  font-size: 1.05em;
}

/* The flex buttons declare their own `gap`, which is what separates icon from
   label there — a flex container discards the whitespace in the markup. These
   three are block/inline, so the whitespace survives and only needs a nudge. */
.homeLabel .bi,
.settingsTab .bi,
.toolDropItem .bi {
  margin-right: 2px;
}

/* Icon-only buttons: no text to sit beside, so drop the nudge. */
#ariaSettingsBtn .bi,
#settingsCloseBtn .bi,
#commandsCloseBtn .bi,
#bgTasksCloseBtn .bi,
.attachInline .bi {
  vertical-align: 0;
  margin-right: 0;
}

.pBtnIcon .bi {
  font-size: 1.15rem;
  vertical-align: 0;
}

/* ============================================================
   BRAND TYPE
   Every ARIA wordmark was a heavy tracked-out Orbitron in accent red.
   It is now the serif display face in text colour, at one size per slot.
   ============================================================ */
.homeTitleMain,
.sidebarLogo,
.chatHeaderARIA,
.bootAriaLogo,
.aboutLogo,
.lockLogo,
.emptyChatLogo {
  /* --font-display is the serif in every mode except Mono, which sets it to
     the mono face so the wordmark matches the rest of that mode. */
  font-family: var(--font-display, var(--font-serif));
  font-weight: 400;
  letter-spacing: 0;
  color: var(--text);
  text-shadow: none;
  animation: none;
}

.homeTitleMain {
  font-size: 1.9rem;
}
.sidebarLogo {
  font-size: 1.4rem;
}
.chatHeaderARIA {
  font-size: 1.05rem;
}

.homeTitleAcronym,
.sidebarAcronym,
.chatHeaderSub,
.bootAcronym,
.aboutAcronym span {
  font-family: var(--font-sans);
  font-size: 0.68rem;
  color: var(--text-3);
  letter-spacing: 0;
  text-transform: none;
}

.aboutAcronym span b,
.bootAcronym span b {
  color: var(--accent-text);
  text-shadow: none;
}

/* ============================================================
   RETIRED DECORATION
   Scanning lines, corner sweeps and pulsing rails were the old chrome.
   ============================================================ */
#chatHeader::after,
#inputBar::before,
#sidebar::before,
#homepageContent::before,
.homeCard::before,
#lockScreen::before {
  content: none;
  display: none;
  animation: none;
}

.sidebarDivider {
  background: var(--border);
}

@keyframes titlePulse {
  0%,
  100% {
    opacity: 1;
  }
}
@keyframes inputGlow {
  0%,
  100% {
    opacity: 1;
  }
}

/* ============================================================
   BARS — sidebar header, chat header, panel headers
   ============================================================ */
#sidebarHeader {
  padding: 10px 4px 12px;
  text-align: left;
  border-bottom: 1px solid var(--border);
  margin-bottom: 10px;
}

#chatHeader {
  background: var(--bg);
  border-bottom: 1px solid var(--border);
  padding: 10px 18px;
}

/* ============================================================
   SURFACES — panels, overlays, popovers, cards
   ============================================================ */
#settingsPanel,
#clawPanel,
#shortcutsPanel,
#mathPanel,
#musicPanel,
#tasksPanel,
.panelCard,
.toolCard,
.featureCard {
  background: var(--bg-card);
  border-color: var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-lg);
}

/* Modal scrims sit on the ground colour, not a red-tinted black.
   #ambientOverlay is deliberately excluded — it is a full-screen mode, not a
   dialog behind-drop, and it needs to stay opaque. */
#shortcutsOverlay,
#clawConfirmOverlay,
#callModeOverlay {
  background: color-mix(in srgb, var(--bg) 82%, transparent);
  backdrop-filter: blur(6px);
}

#ambientOverlay {
  background: color-mix(in srgb, var(--bg) 92%, transparent);
}

/* ============================================================
   FIELDS
   One shape for every text-entry surface in the app.
   ============================================================ */
input[type="text"],
input[type="number"],
input[type="email"],
input[type="password"],
input[type="search"],
input[type="url"],
textarea,
select,
.settingsTextInput,
.cwHexInput {
  background: var(--bg-inset);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  color: var(--text);
  font-family: var(--font-sans);
  outline: none;
  transition: border-color var(--tr);
}

input:focus,
textarea:focus,
select:focus,
.settingsTextInput:focus,
.cwHexInput:focus {
  border-color: var(--accent-text);
  box-shadow: none;
}

input::placeholder,
textarea::placeholder {
  color: var(--text-3);
}

input[type="range"] {
  accent-color: var(--accent);
}

/* ============================================================
   BUTTON-LIKE CONTROLS
   The app's many one-off button classes converge on BookWare's pill.
   ============================================================ */
.themeSwatch,
.emotionOverrideBtn,
.dangerBtn,
.cwSaveBtn,
.esp32SendCmdBtn,
.toolBtn,
.chipBtn {
  font-family: var(--font-sans);
  letter-spacing: 0.02em;
  text-transform: none;
  cursor: pointer;
  border-radius: var(--r-sm);
  transition: background var(--tr), border-color var(--tr), color var(--tr);
}

.themeSwatch,
.emotionOverrideBtn,
.esp32SendCmdBtn,
.chipBtn {
  border-radius: var(--r-full);
  background: var(--bg-inset);
  border: 1px solid var(--border);
  color: var(--text-2);
}

.themeSwatch:hover,
.emotionOverrideBtn:hover,
.esp32SendCmdBtn:hover,
.chipBtn:hover {
  border-color: var(--accent-text);
  color: var(--accent-text);
  background: var(--bg-inset);
  box-shadow: none;
}

.themeSwatch.active,
.emotionOverrideBtn.active,
.chipBtn.active {
  border-color: var(--accent-text);
  color: var(--accent-text);
  background: var(--accent-bg);
  box-shadow: none;
}

/* Danger keeps its own semantic colour rather than the accent. */
.dangerBtn {
  background: var(--danger-bg);
  border: 1px solid var(--danger-border);
  color: var(--danger-text);
  border-radius: var(--r-full);
}
.dangerBtn:hover {
  background: var(--danger);
  color: #fff;
  border-color: var(--danger);
  box-shadow: none;
}

/* Claw kill switch — a real destructive control, so it keeps the danger
   colour, but as a bordered chip rather than a glowing orb. */
#clawKillSwitch {
  background: var(--bg-card);
  border: 1px solid var(--danger-border);
  color: var(--danger-text);
  font-family: var(--font-sans);
  font-size: 0.55rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  box-shadow: var(--shadow);
}
#clawKillSwitch:hover {
  background: var(--danger);
  border-color: var(--danger);
  color: #fff;
  box-shadow: var(--shadow);
  transform: none;
}
#clawKillSwitch.killed {
  background: var(--danger);
  border-color: var(--danger);
  color: #fff;
  animation: killPulse 1.6s ease-in-out infinite;
}
@keyframes killPulse {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.6;
  }
}

/* ARIA halo — state feedback, so it stays, but as a hairline frame instead
   of a 60px neon bloom. */
#ariaHalo.thinking,
#ariaHalo.speaking,
#ariaHalo.pulse {
  box-shadow: none;
  border: 1px solid var(--accent-border);
}
@keyframes haloThink {
  0%,
  100% {
    opacity: 0.35;
  }
  50% {
    opacity: 0.8;
  }
}
@keyframes haloSpeak {
  from {
    opacity: 0.4;
  }
  to {
    opacity: 0.85;
  }
}

/* Round dots stay round — the notch rewrite squared a few of them off. */
.swatchDot,
.esp32StatusDot,
.statusDot {
  border-radius: 50%;
  box-shadow: none;
}

/* ============================================================
   SIDEBAR COLLAPSE BUTTON
   It was a 20px sliver pinned to right:0 with the right border removed —
   a tab meant to straddle the sidebar edge. Once the notch clip-path
   became a border-radius it stopped reading as a tab and started reading
   as a stray rounded box.
   ============================================================ */
#sidebarCollapseBtn {
  width: 22px;
  height: 44px;
  background: var(--bg-inset);
  border: 1px solid var(--border);
  /* Rounded on the inboard side only, so it still reads as a tab attached
     to the sidebar edge rather than a floating pill. */
  border-radius: var(--r) 0 0 var(--r);
  border-right: none;
  color: var(--text-3);
  font-size: 0.75rem;
}
#sidebarCollapseBtn:hover {
  background: var(--bg-hover);
  border-color: var(--border-strong);
  color: var(--accent-text);
}

#sidebarCollapseIcon {
  display: flex;
  align-items: center;
  justify-content: center;
  letter-spacing: 0;
  transition: transform var(--tr-slow);
}

/* Collapsed, the sidebar is a 40px rail and the button is all that's in
   it — so it becomes a centred pill instead of an edge tab. right:0 is
   measured from the padding box, which left it 8px from one edge and
   12px from the other: the off-centre look. */
#sidebar.collapsed #sidebarCollapseBtn {
  right: auto;
  /* An absolutely positioned child centres on its containing block, which is
     the sidebar's PADDING box. That box excludes the 1px right border, so its
     centre sits half a pixel LEFT of the centre of the 40px rail you actually
     see. Adding it back lands the button on the visual centre. */
  left: calc(50% + 0.5px);
  transform: translate(-50%, -50%);
  width: 28px;
  height: 40px;
  border-radius: var(--r-sm);
  border-right: 1px solid var(--border);
}

#sidebar.collapsed #sidebarCollapseIcon {
  transform: rotate(180deg);
}

/* ============================================================
   COMPOSER ROW
   The textarea and the buttons beside it were sized independently —
   38px against 34px — and the row is bottom-aligned so the textarea can
   grow upward as you type. At rest that left the input standing a few
   pixels proud of the buttons. One shared height fixes the resting
   state without breaking the growth behaviour.
   ============================================================ */
#userInput {
  min-height: var(--input-h) !important;
  padding: 9px 14px;
  line-height: 1.4;
  /* A textarea is inline-block by default, so its wrapper reserves a few
     pixels of descender space underneath it. The row is bottom-aligned, so
     that gap pushed the field up off the button baseline even once the
     heights matched. */
  display: block;
}

#inputBtnRow .voiceBtn,
#inputBtnRow .primaryBtn,
#inputBtnRow .secondaryBtn,
#sendBtn {
  min-height: var(--input-h);
  height: var(--input-h);
}

/* The paperclip rides inside the textarea, so centre it on the resting
   height rather than pinning it to the bottom edge. */
.attachInline {
  bottom: auto;
  top: calc(var(--input-h) / 2);
  transform: translateY(-50%);
  display: flex;
  align-items: center;
  color: var(--text-3);
  opacity: 1;
  font-size: 0.95rem;
}
.attachInline:hover {
  color: var(--accent-text);
}

/* ============================================================
   MESSAGE HEADER
   One row: sender on the left, timestamp and actions on the right,
   all on a single baseline.
   ============================================================ */
.msgHeader {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 6px;
  min-height: 18px;
}

.msgMeta {
  display: flex;
  align-items: center;
  gap: 2px;
  flex-shrink: 0;
}

/* The buttons fade in on hover, but the timestamp is always readable —
   it used to fade with them because it shared the container. */
.msgMeta .msgActionBtn {
  opacity: 0;
  transition: opacity var(--tr), color var(--tr), background var(--tr);
}
.msg:hover .msgMeta .msgActionBtn,
.msgActionBtn:focus-visible {
  opacity: 1;
}

.msgActionBtn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  padding: 0;
  margin-left: 2px;
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--r-sm);
  color: var(--text-3);
  font-size: 0.72rem;
  line-height: 1;
  cursor: pointer;
}
.msgActionBtn:hover {
  color: var(--accent-text);
  background: var(--bg-inset);
}
.msg.user .msgActionBtn {
  color: rgba(255, 255, 255, 0.65);
}
.msg.user .msgActionBtn:hover {
  color: #fff;
  background: rgba(0, 0, 0, 0.18);
}
.msgActionBtn.active {
  color: var(--warning);
  opacity: 1;
}
.msgDeleteBtn:hover {
  color: var(--danger-text);
  border-color: transparent;
}
.msgRegenBtn:hover {
  color: var(--success-text);
  border-color: transparent;
}

.msgPinBadge,
.msgStarBadge {
  font-size: 0.7rem;
  line-height: 1;
}

/* ============================================================
   VISUALIZATIONS
   Model-authored widgets, rendered in a sandboxed frame. Everything
   here is the chrome around that frame — the frame's own styling is
   injected in js/visualize.js, since it lives in a separate document.
   ============================================================ */
.msgVisual {
  margin: 10px 0 4px;
  border: 1px solid var(--border);
  border-radius: var(--r);
  background: var(--bg-card);
  overflow: hidden;
}

.msgVisualHead {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 8px 12px;
  border-bottom: 1px solid var(--border);
}

.msgVisualTitle {
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-3);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.msgVisualActions {
  display: flex;
  gap: 4px;
  flex-shrink: 0;
}

.msgVisualBtn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  padding: 0;
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--r-sm);
  color: var(--text-3);
  cursor: pointer;
  font-size: 0.8rem;
  transition: color var(--tr), border-color var(--tr), background var(--tr);
}
.msgVisualBtn:hover {
  color: var(--accent-text);
  border-color: var(--border);
  background: var(--bg-inset);
}

.msgVisualFrame {
  display: block;
  width: 100%;
  height: 200px;
  border: 0;
  background: transparent;
  /* Height is driven by a postMessage from inside the frame, so ease the
     jump when a widget reflows after its scripts run. */
  transition: height 0.2s ease;
}

.msgVisualSource {
  margin: 0;
  border: 0;
  border-top: 1px solid var(--border);
  border-radius: 0;
  max-height: 320px;
  overflow: auto;
  padding: 12px;
  font-size: 0.72rem;
  white-space: pre;
}

/* ============================================================
   SPEED TEST GAUGE
   The dial the speed test draws while it runs. Geometry lives in
   js/speedGauge.js; this is colour, weight and state.
   ============================================================ */
.speedGaugeWrap {
  display: flex;
  justify-content: center;
  margin: 2px 0 4px;
}

.speedGauge {
  overflow: visible;
  max-width: 100%;
  height: auto;
}

.speedGauge .sgTrack,
.speedGauge .sgFill {
  fill: none;
  stroke-width: 9;
  stroke-linecap: round;
}

.speedGauge .sgTrack {
  stroke: var(--bg-inset);
}

.speedGauge .sgFill {
  stroke: var(--accent);
  /* pathLength is normalised to 1 in the markup, so the dash offset is just
     "how much of the arc is left" — no need to know the real path length. */
  transition: stroke-dashoffset 0.25s ease;
}

.speedGauge .sgTick {
  stroke: var(--border-strong);
  stroke-width: 1.5;
  stroke-linecap: round;
}

.speedGauge .sgTickLabel {
  fill: var(--text-3);
  font-family: var(--font-sans);
  font-size: 9px;
  text-anchor: middle;
  dominant-baseline: middle;
}

.speedGauge .sgNeedle {
  stroke: var(--text);
  stroke-width: 2.5;
  stroke-linecap: round;
  transform-box: view-box;
}

.speedGauge .sgNeedleGroup {
  transition: transform 0.25s ease;
}

.speedGauge .sgHub {
  fill: var(--text);
}

.speedGauge .sgValue {
  fill: var(--text);
  font-family: var(--font-sans);
  font-size: 30px;
  font-weight: 600;
  text-anchor: middle;
}

.speedGauge .sgUnit {
  fill: var(--text-3);
  font-family: var(--font-sans);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.13em;
  text-anchor: middle;
}

/* ── States ── */
.speedGauge[data-state="idle"] .sgFill {
  stroke: var(--border-strong);
}
.speedGauge[data-state="idle"] .sgNeedle,
.speedGauge[data-state="idle"] .sgHub {
  stroke: var(--text-3);
  fill: var(--text-3);
}

/* Live: no easing, or the needle lags behind its own samples. */
.speedGauge[data-state="running"] .sgFill,
.speedGauge[data-state="running"] .sgNeedleGroup {
  transition-duration: 0.12s;
}

.speedGauge[data-state="failed"] .sgFill {
  stroke: var(--danger-border);
}
.speedGauge[data-state="failed"] .sgValue {
  fill: var(--text-3);
}

/* ── Readout row under the dial ── */
.speedReadout {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-top: 2px;
}

.speedPing {
  font-size: 0.75rem;
  color: var(--text-2);
  font-variant-numeric: tabular-nums;
}
.speedPing::before {
  content: "Ping ";
  color: var(--text-3);
  font-size: 0.6rem;
  font-weight: 600;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.speedGoBtn {
  padding: 5px 14px;
  min-height: 28px;
  background: var(--accent);
  border: 1px solid var(--accent);
  border-radius: var(--r-full);
  color: #fff;
  font-family: var(--font-sans);
  font-size: 0.7rem;
  font-weight: 500;
  cursor: pointer;
  white-space: nowrap;
  transition: opacity var(--tr), background var(--tr), color var(--tr);
}
.speedGoBtn:hover {
  opacity: 0.88;
}
.speedGoBtn.running {
  background: transparent;
  border-color: var(--border-strong);
  color: var(--text-2);
}

/* ============================================================
   HOME-TOOL WIDGETS
   These are generated by homeTools.js and never had CSS of their own,
   so they were rendering as raw Bootstrap buttons and unstyled spans.
   ============================================================ */
.hwToolBtn,
.codeCopyBtn,
.codeDownloadBtn,
.codePanelBtn,
.clipCopy,
.clipDel,
.mgZoomIn,
.mgZoomOut,
.mgReset {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 5px 11px;
  min-height: 26px;
  background: var(--bg-inset);
  border: 1px solid var(--border);
  border-radius: var(--r-full);
  color: var(--text-2);
  font-family: var(--font-sans);
  font-size: 0.68rem;
  font-weight: 500;
  line-height: 1.2;
  cursor: pointer;
  white-space: nowrap;
  transition: border-color var(--tr), color var(--tr), background var(--tr);
}

.hwToolBtn:hover,
.codeCopyBtn:hover,
.codeDownloadBtn:hover,
.codePanelBtn:hover,
.clipCopy:hover,
.clipDel:hover,
.mgZoomIn:hover,
.mgZoomOut:hover,
.mgReset:hover {
  border-color: var(--accent-text);
  color: var(--accent-text);
}

.hwEmpty {
  display: block;
  font-size: 0.75rem;
  color: var(--text-3);
  line-height: 1.6;
}

.hwSub {
  font-size: 0.72rem;
  color: var(--text-3);
  line-height: 1.6;
}

.hw-lg {
  font-size: 1.05rem;
  color: var(--text);
  font-weight: 500;
}

.hwListItem {
  padding: 5px 0;
  font-size: 0.76rem;
  color: var(--text-2);
  border-bottom: 1px solid var(--border);
  line-height: 1.5;
}
.hwListItem:last-child {
  border-bottom: none;
}
.hwListClickable {
  cursor: pointer;
  border-radius: var(--r-sm);
  padding: 5px 6px;
  transition: background var(--tr), color var(--tr);
}
.hwListClickable:hover {
  background: var(--bg-hover);
  color: var(--text);
}

.htWidget {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.htWidgetLabel {
  font-size: 0.6rem;
  font-weight: 600;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--text-3);
}
.htWidgetValue {
  font-size: 0.9rem;
  color: var(--text);
}

/* Data rows shared by the crypto / clock / dictionary widgets */
.cryptoRow,
.worldClockRow,
.clipItem {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 0;
  font-size: 0.76rem;
  color: var(--text-2);
  border-bottom: 1px solid var(--border);
}
.cryptoRow:last-child,
.worldClockRow:last-child,
.clipItem:last-child {
  border-bottom: none;
}
.cryptoSym,
.worldClockCity,
.dictWord {
  font-weight: 600;
  color: var(--text);
}
.cryptoPrice,
.worldClockTime {
  margin-left: auto;
  font-family: var(--font-mono-stack);
  color: var(--text);
}
.worldClockDiff,
.dictPos {
  font-size: 0.68rem;
  color: var(--text-3);
}
.dictMeaning {
  font-size: 0.76rem;
  color: var(--text-2);
  line-height: 1.6;
}
.clipText {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ============================================================
   CODE SURFACES
   The global font sweep moved everything to DM Sans; code goes back.
   ============================================================ */
.codeBlock,
code,
code.inlineCode,
pre,
pre.clawEntryText,
kbd,
.text-input--mono,
.cwHexInput,
.cwHsl {
  font-family: var(--font-mono-stack);
}

code.inlineCode {
  background: var(--bg-inset);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 1px 5px;
  color: var(--accent-text);
  font-size: 0.85em;
}

.codeBlock,
pre.clawEntryText {
  background: var(--bg-inset);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  color: var(--text);
}

/* ============================================================
   SCROLLBARS
   theme-modes.css paints these in the accent; the design system wants
   them to disappear into the border colour.
   ============================================================ */
::-webkit-scrollbar {
  width: 6px;
  height: 6px;
}
::-webkit-scrollbar-track {
  background: transparent;
}
::-webkit-scrollbar-thumb {
  background: var(--border);
  border-radius: var(--r-full);
}
::-webkit-scrollbar-thumb:hover {
  background: var(--border-strong);
}

/* ============================================================
   MEMORY / TASK / LIST ROWS
   ============================================================ */
.memFact,
.customVoiceItem,
.esp32DeviceCard,
.taskRow {
  background: var(--bg-inset);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  font-family: var(--font-sans);
}

.memFact {
  border-left: 2px solid var(--border);
}
.memFact.pinned {
  border-left-color: var(--accent);
  background: var(--accent-bg);
}

.memCategory {
  font-family: var(--font-sans);
  font-size: 0.6rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent-text);
  border: 1px solid var(--accent-border);
  border-radius: var(--r-full);
  padding: 2px 7px;
}

.memEmpty {
  font-family: var(--font-sans);
  border: 1px dashed var(--border);
  border-radius: var(--r-sm);
  color: var(--text-3);
}

/* ============================================================
   ABOUT BLOCK
   ============================================================ */
.aboutBlock {
  border: 1px solid var(--border);
  border-radius: var(--r);
  background: var(--bg-card);
  padding: 18px;
}

.aboutVersion {
  font-family: var(--font-sans);
  font-size: 0.6rem;
  font-weight: 600;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--text-3);
}

/* ============================================================
   THEME PICKER (settings)
   ============================================================ */
.themeModeCard {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--r);
}
.themeModeCard:hover {
  border-color: var(--border-strong);
  transform: none;
}
.themeModeCard.active {
  border-color: var(--accent-text);
  background: var(--accent-bg);
  box-shadow: none;
}
.themeModeCard.active::after {
  color: var(--accent-text);
}
.themeModeLabel {
  font-weight: 600;
  color: var(--text);
}
.themeModeDesc {
  font-size: 0.7rem;
  color: var(--text-3);
}

/* The grid is aspect-ratio 1 across 8 columns, which in an 820px panel makes
   each swatch ~95px tall — a wall of colour. Cap the height instead. */
.accentColorGrid {
  grid-template-columns: repeat(auto-fill, minmax(56px, 1fr));
  gap: 8px;
  margin: 8px 0 22px;
}
.themeSwatchV2 {
  aspect-ratio: auto;
  height: 34px;
  border-radius: var(--r-sm);
}
.themeSwatchV2:hover {
  transform: none;
  outline: 1px solid var(--border-strong);
  outline-offset: 2px;
}
.themeSwatchV2.active {
  border-color: transparent;
  outline: 2px solid var(--text);
  outline-offset: 2px;
  box-shadow: none;
}

.colorWheelV2 {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--r);
}
.cwSwatch {
  border: 1px solid var(--border);
  box-shadow: none;
  border-radius: var(--r-sm);
}
.cwSaveBtn {
  background: var(--accent);
  border: 1px solid var(--accent);
  color: #fff;
  border-radius: var(--r-full);
}
.cwSaveBtn:hover {
  opacity: 0.88;
  background: var(--accent);
  color: #fff;
}

/* ============================================================
   MOTION
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* ============================================================
   SOURCES
   The pages the research agent actually fetched, listed under the
   answer. Deliberately quiet — it is provenance, not content — but
   always present when research ran, so a citation can be checked.
   ============================================================ */
.msgSources {
  margin: 12px 0 2px;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: var(--r);
  background: var(--bg-card);
}

.msgSourcesHead {
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-3);
  margin-bottom: 6px;
}

.msgSourcesList {
  margin: 0;
  padding-left: 20px;
  font-size: 0.82rem;
  line-height: 1.6;
}

.msgSourcesList li::marker {
  color: var(--text-3);
}

.msgSourcesList a {
  color: var(--accent-text);
  text-decoration: none;
}

.msgSourcesList a:hover {
  text-decoration: underline;
}

.msgSourceHost {
  color: var(--text-3);
  font-size: 0.74rem;
}

/* A page that could not be read still earns its line — the gap in the
   evidence is part of the answer. */
.msgSourceFailed a {
  color: var(--text-3);
  text-decoration: line-through;
}

/* ============================================================
   TOOL CALLS — above a reply, see createToolCallList() in chat.js
   ============================================================ */
.msgToolCalls {
  margin: 2px 0 10px;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: var(--r);
  background: var(--bg-card);
  font-size: 0.8rem;
}
.msgToolCalls--nested {
  margin: 6px 0;
  background: var(--bg-inset);
}
.msgToolCallsHead {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-3);
  cursor: pointer;
}
.toolCallList {
  list-style: none;
  margin: 6px 0 0;
  padding: 0;
}
.toolCall + .toolCall {
  border-top: 1px solid var(--border);
}
.toolCallSummary {
  display: flex;
  align-items: center;
  gap: 7px;
  min-width: 0;
  padding: 5px 2px;
  cursor: pointer;
  color: var(--text-2);
}
.toolCallSummary,
.msgToolCallsHead {
  list-style: none; /* Firefox's disclosure triangle */
}
.toolCallSummary::-webkit-details-marker,
.msgToolCallsHead::-webkit-details-marker {
  display: none;
}
.toolCallSummary:hover {
  color: var(--text);
}
.toolCallName {
  font-family: var(--font-mono-stack);
  font-size: 0.76rem;
  color: var(--text);
  flex-shrink: 0;
}
.toolCallInput {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text-3);
}
.toolCallMs {
  flex-shrink: 0;
  font-size: 0.7rem;
  color: var(--text-3);
}
.toolCall--ok .toolCallStatus {
  color: var(--success-text);
}
.toolCall--error .toolCallStatus {
  color: var(--danger-text);
}
.toolCall--blocked .toolCallStatus,
.toolCall--held .toolCallStatus {
  color: var(--warning-text);
}
.toolCallBody {
  padding: 2px 0 8px 22px;
}
.toolCallLabel {
  margin: 6px 0 3px;
  font-size: 0.66rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-3);
}
.toolCallPre {
  margin: 0;
  max-height: 220px;
  overflow: auto;
  padding: 6px 8px;
  border-radius: var(--r-sm);
  background: var(--bg-inset);
  color: var(--text-2);
  font-family: var(--font-mono-stack);
  font-size: 0.72rem;
  line-height: 1.5;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
/* A nested list already sits on the inset colour. */
.msgToolCalls--nested .toolCallPre {
  background: var(--bg-card);
}
.toolCallPages {
  margin: 0;
  padding-left: 20px;
  font-size: 0.76rem;
  line-height: 1.6;
}
.toolCallPages a {
  color: var(--accent-text);
  text-decoration: none;
}
.toolCallPages a:hover {
  text-decoration: underline;
}
.toolCallPageFailed,
.toolCallPageFailed a {
  color: var(--text-3);
}
.toolCallAgent {
  margin: 6px 0 0;
  padding: 2px 8px;
  border-left: 2px solid var(--border-strong);
}
.toolCallAgent--error {
  border-left-color: var(--danger);
}

/* ============================================================
   CODE BLOCKS IN MESSAGES
   overlays.css still dressed these the old way: a neon left bar, an
   inset red glow, 2px corners, a tinted uppercase label — and, most
   visibly, `font-family: var(--font-sans)` on the code itself, which
   beat the mono rule above on specificity and rendered every snippet
   in the body font. The selectors here match that specificity so the
   design system wins without editing the legacy file.
   ============================================================ */
.msgBody .codeBlock {
  position: relative;
  /* panels.css reserves 30px of top padding for absolutely positioned
     action buttons; the header row below is a real element instead. */
  padding-top: 0 !important;
  background: var(--bg-inset);
  border: 1px solid var(--border);
  border-left: 1px solid var(--border);
  border-radius: var(--r-sm);
  box-shadow: none;
  margin: 12px 0;
  overflow: hidden;
}

.codeBlockHead {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px 6px 12px;
  background: var(--bg-card);
  border-bottom: 1px solid var(--border);
}

.msgBody .codeBlock .codeLabel {
  display: inline-block;
  padding: 0;
  background: none;
  border: 0;
  font-family: var(--font-mono-stack);
  font-size: 0.68rem;
  letter-spacing: 0.06em;
  color: var(--text-3);
}

/* A block whose closing fence never arrived, because the reply hit the
   token limit. Saying so beats the reader assuming the code is complete. */
.codeTruncatedFlag {
  font-size: 0.62rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--warning-text);
  border: 1px solid var(--border);
  border-radius: var(--r-full);
  padding: 1px 7px;
}

.msgBody .codeBlock .codeActions {
  position: static;
  margin-left: auto;
  gap: 4px;
}

.codeActionBtn {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  background: var(--bg-inset);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  color: var(--text-2);
  font-family: var(--font-sans);
  font-size: 0.7rem;
  padding: 3px 9px;
  cursor: pointer;
  transition: color var(--tr), border-color var(--tr), background var(--tr);
}
.codeActionBtn:hover {
  background: var(--bg-hover);
  border-color: var(--border-strong);
  color: var(--text);
}

.msgBody .codeBlock pre {
  margin: 0;
  padding: 12px 14px;
  background: transparent;
}

.msgBody .codeBlock code,
#codePanelContent {
  font-family: var(--font-mono-stack);
  font-size: 0.78rem;
  line-height: 1.6;
  color: var(--text);
}

/* ============================================================
   CODE PANEL
   ============================================================ */
#codePanel {
  background: var(--bg-card);
  border-left: 1px solid var(--border);
}
#codePanel.open {
  border-left-color: var(--border);
  box-shadow: var(--shadow-lg);
}
#codePanelHeader {
  background: var(--bg-card);
  border-bottom: 1px solid var(--border);
}
#codePanelLang {
  font-family: var(--font-mono-stack);
  font-size: 0.7rem;
  letter-spacing: 0.06em;
  color: var(--text-3);
}
.codePanelActions button {
  border-radius: var(--r-sm);
  border-color: var(--border);
  font-size: 0.72rem;
}
.codePanelActions button:hover {
  background: var(--bg-hover);
  border-color: var(--border-strong);
  color: var(--text);
  box-shadow: none;
}
#codePanelContent {
  background: var(--bg-inset);
}
/* The previewed document paints its own themed ground; a white frame
   behind it flashed on every toggle. */
#codePanelPreviewFrame {
  background: var(--bg-inset);
}

/* ============================================================
   DIALOGS
   The command palette, the background-task board and the quick modal
   were built before the design system: a red 1px outline, a neon glow
   and a red uppercase title. Every other surface in the app is a card
   on a blurred scrim, so these become that.
   ============================================================ */
#commandsModal,
#bgTasksModal,
#ariaQuickModal {
  background: color-mix(in srgb, var(--bg) 82%, transparent);
  backdrop-filter: blur(6px);
}

#commandsPanel,
#bgTasksPanel,
#ariaQuickModalInner {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-lg);
}

#commandsHeader,
#bgTasksHeader,
#ariaQuickModalHeader {
  background: transparent;
  border-bottom: 1px solid var(--border);
  padding: 14px 18px;
}

#commandsHeader h2,
#bgTasksHeader h2,
#ariaQuickModalTitle {
  font-family: var(--font-sans);
  font-size: 0.9rem;
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  color: var(--text);
}

/* One close button, matching the icon buttons everywhere else. */
#commandsHeader button,
#bgTasksHeader button,
#ariaQuickModalClose {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  color: var(--text-2);
  font-size: 0.85rem;
  cursor: pointer;
  transition: color var(--tr), border-color var(--tr), background var(--tr);
}
#commandsHeader button:hover,
#bgTasksHeader button:hover,
#ariaQuickModalClose:hover {
  background: var(--bg-hover);
  border-color: var(--border-strong);
  color: var(--text);
}

#commandsList,
#bgTasksList,
#ariaQuickModalBody {
  padding: 14px 18px;
}

.commandItem {
  border-bottom: 1px solid var(--border);
  padding: 9px 0;
}
.commandName {
  font-family: var(--font-mono-stack);
  font-size: 0.78rem;
  color: var(--text);
}
.commandDesc {
  font-size: 0.78rem;
  color: var(--text-2);
}

/* ============================================================
   INSTALL BUTTON
   Appears in the chat header only while the browser is actually
   offering to install (see js/installApp.js), so it must not hold
   layout when hidden.
   ============================================================ */
#installAppBtn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--accent-bg);
  border: 1px solid var(--accent-border);
  border-radius: var(--r-full);
  color: var(--accent-text);
  font-family: var(--font-sans);
  font-size: 0.72rem;
  padding: 4px 12px;
  margin-right: 4px;
  cursor: pointer;
  transition: background var(--tr), border-color var(--tr);
}
#installAppBtn:hover {
  background: color-mix(in srgb, var(--accent) 18%, transparent);
  border-color: var(--accent);
}
#installAppBtn:disabled {
  opacity: 0.6;
  cursor: default;
}

/* ============================================================
   MODEL SWITCHER — chat header, see js/modelSwitcher.js
   ============================================================ */
#modelSwitchWrap {
  position: relative;
  min-width: 0;
}
#modelSwitchBtn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  max-width: 220px;
  background: var(--bg-inset);
  border: 1px solid var(--border);
  border-radius: var(--r-full);
  color: var(--text-2);
  font-family: var(--font-sans);
  font-size: 0.72rem;
  padding: 4px 10px;
  cursor: pointer;
  transition: border-color var(--tr), color var(--tr), background var(--tr);
}
#modelSwitchBtn:hover,
#modelSwitchBtn[aria-expanded="true"] {
  border-color: var(--accent-text);
  color: var(--accent-text);
  background: var(--accent-bg);
}
#modelSwitchLabel {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
#modelSwitchBtn .bi-chevron-down {
  font-size: 0.8em;
}
/* A PC model is picked but the hook isn't connected, so replies are coming
   from a cloud fallback. */
#modelSwitchBtn.modelSwitchOffline {
  border-color: var(--warning);
  color: var(--warning-text);
}
/* Fixed, not absolute: js/modelSwitcher.js places it against the viewport
   so it can't run off either edge of a phone screen. */
#modelSwitchMenu {
  position: fixed;
  z-index: 600;
  width: max-content;
  min-width: min(240px, calc(100vw - 32px));
  max-width: min(340px, calc(100vw - 32px));
  max-height: min(70vh, 520px);
  overflow-y: auto;
  padding: 4px 0;
  background: var(--bg-card);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-sm);
  box-shadow: var(--shadow-lg);
}
.modelSwitchHeading {
  padding: 8px 14px 4px;
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-3);
}
.toolDropItem.modelSwitchItem {
  display: flex;
  align-items: center;
  gap: 8px;
  color: var(--text);
}
.toolDropItem.modelSwitchItem[aria-checked="true"] {
  color: var(--accent-text);
}
.toolDropItem.modelSwitchItem:disabled {
  opacity: 0.45;
  cursor: default;
}
.toolDropItem.modelSwitchItem:disabled:hover {
  padding-left: 14px;
  background: transparent;
}
.modelSwitchName {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.modelSwitchSub {
  font-size: 10px;
  color: var(--text-3);
}
.modelSwitchNote {
  padding: 6px 14px 10px;
  font-size: 11px;
  line-height: 1.5;
  color: var(--text-2);
}
.modelSwitchNote code {
  font-size: 10px;
  overflow-wrap: anywhere;
}
@media (max-width: 600px) {
  #modelSwitchBtn {
    max-width: 130px;
  }
}
