/* Feature styles moved out of styles.css (media viewer, forwarding,
   quick switcher extras, pins, jump bars, a11y, markup extensions,
   components, forgejo, economy, AI surfaces, …). Loaded after
   styles.css so the cascade order is unchanged. */
/* ============ media viewer (lightbox) ============ */
.media-viewer {
  position: fixed; inset: 0; z-index: 300; background: rgba(0,0,0,0.85);
  display: grid; place-items: center; overflow: hidden;
  animation: mv-fade calc(150ms * var(--anim)) var(--ease);
}
.media-viewer.closing { opacity: 0; transition: opacity calc(120ms * var(--anim)) var(--ease); }
@keyframes mv-fade { from { opacity: 0; } }
.mv-stage {
  position: absolute; inset: 0; display: grid; place-items: center;
  padding: 48px 72px; pointer-events: none;
}
.mv-media {
  max-width: calc(100vw - 144px); max-height: calc(100vh - 96px);
  object-fit: contain; border-radius: var(--radius-sm); pointer-events: auto;
  animation: mv-in calc(150ms * var(--anim)) var(--ease); user-select: none;
}
@keyframes mv-in { from { opacity: 0; transform: scale(.96); } }
img.mv-media { cursor: zoom-in; transition: transform calc(150ms * var(--anim)) var(--ease); }
img.mv-media.zoomed { cursor: zoom-out; max-width: none; max-height: none; transition: transform calc(150ms * var(--anim)) var(--ease); touch-action: none; }
img.mv-media.zoomed.panning { cursor: grabbing; transition: none; }
video.mv-media { max-width: calc(100vw - 144px); max-height: calc(100vh - 96px); outline: none; }
.mv-toolbar {
  position: absolute; top: 0; left: 0; right: 0; z-index: 2;
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 14px 16px; pointer-events: none;
}
.mv-name {
  color: var(--text-header); font-size: 14px; font-weight: 600;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0;
  text-shadow: 0 1px 2px rgba(0,0,0,.6); pointer-events: auto;
}
.mv-actions { display: flex; gap: 10px; flex: none; pointer-events: auto; }
.mv-btn {
  width: 36px; height: 36px; border-radius: 50%; display: grid; place-items: center;
  background: #2b2d31cc; color: var(--text-normal); transition: background-color calc(120ms * var(--anim)) var(--ease), color calc(120ms * var(--anim)) var(--ease);
}
.mv-btn:hover { background: var(--bg-active); color: var(--text-header); text-decoration: none; }
.mv-nav {
  position: absolute; top: 50%; transform: translateY(-50%); z-index: 2;
  width: 48px; height: 48px; border-radius: 50%; display: grid; place-items: center;
  background: #2b2d31cc; color: var(--text-normal); transition: background-color calc(120ms * var(--anim)) var(--ease), color calc(120ms * var(--anim)) var(--ease);
}
.mv-nav:hover { background: var(--bg-active); color: var(--text-header); }
.mv-prev { left: 16px; }
.mv-next { right: 16px; }
.mv-counter {
  position: absolute; bottom: 18px; left: 50%; transform: translateX(-50%); z-index: 2;
  color: var(--text-header); font-size: 13px; font-weight: 600;
  background: #2b2d31cc; border-radius: var(--radius-2xl); padding: 4px 12px; user-select: none;
}
/* hover affordance on inline video attachments opens the viewer */
.msg-video-wrap { position: relative; display: inline-block; margin-top: 4px; }
.msg-video-wrap .msg-video { margin-top: 0; }
.msg-video-expand {
  position: absolute; top: 8px; right: 8px; width: 32px; height: 32px; border-radius: var(--radius-md);
  display: grid; place-items: center; background: rgba(0,0,0,.55); color: #fff;
  opacity: 0; transition: opacity calc(120ms * var(--anim)) var(--ease), background-color calc(120ms * var(--anim)) var(--ease);
}
.msg-video-wrap:hover .msg-video-expand, .msg-video-wrap:focus-within .msg-video-expand { opacity: 1; }
.msg-video-expand:hover { background: rgba(0,0,0,.8); }
.avatar-zoomable { cursor: zoom-in; }

/* ---- quick switcher extras (recents, protip) ---- */
.qs-section {
  color: var(--text-muted); font-size: 11px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .02em; padding: 8px 10px 4px;
}
.qs-footer { justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 8px; }
.qs-protip { display: flex; align-items: center; gap: 5px; }
.qs-protip b { color: var(--text-normal); }
.qs-footer-keys { white-space: nowrap; }

/* ---- member list extras (count header, mention button, context hint) ---- */
.member-count-header {
  color: var(--text-muted); font-size: 12px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .02em; padding: 8px 8px 10px; border-bottom: 1px solid #232428; margin-bottom: 10px;
}
.toast.success { background: var(--status-online, #23a559); color: #fff; }

/* friend rows: Discord reveals the action buttons on hover */
.friend-row .friend-actions { opacity: 0; transition: opacity calc(100ms * var(--anim)) var(--ease); }
.friend-row:hover .friend-actions, .friend-row:focus-within .friend-actions { opacity: 1; }

/* ---- friend picker (create group DM / add members) ---- */
.friend-pick-list {
  display: flex; flex-direction: column; gap: 2px;
  max-height: 320px; overflow-y: auto; margin: 10px 0;
  border: 1px solid var(--divider); border-radius: var(--radius-lg); padding: 4px;
  background: var(--bg-deepest);
}
.friend-pick { display: flex; align-items: center; gap: 4px; padding-right: 8px; border-radius: var(--radius-md); cursor: pointer; }
.friend-pick:hover { background: var(--bg-hover); }
.friend-pick input { margin-left: 8px; accent-color: var(--brand); flex: none; }
.friend-pick-row { display: flex; align-items: center; gap: 8px; padding: 6px 4px; min-width: 0; flex: 1; }
.friend-pick-row > span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.friend-pick-row .muted { flex: none; }

/* ---- message forwarding (forward chip + forward modal) ---- */
.forward-wrap { margin-top: 4px; }
.forward-label {
  display: flex; align-items: center; gap: 4px; color: var(--text-muted);
  font-size: 12px; font-weight: 600; margin-bottom: 2px; user-select: none;
}
.forward-label .lucide { flex: none; }
.forward-chip {
  background: var(--bg-embed); border: 1px solid var(--bg-deepest); border-radius: var(--radius-lg);
  padding: 8px 12px 10px; max-width: 520px; width: fit-content;
}
.forward-chip.jumpable { cursor: pointer; transition: background calc(100ms * var(--anim)) var(--ease), border-color calc(100ms * var(--anim)) var(--ease); }
.forward-chip.jumpable:hover { background: var(--bg-hover); border-color: var(--divider); }
.forward-head { display: flex; align-items: center; gap: 6px; margin-bottom: 2px; }
.forward-head .avatar { width: 20px; height: 20px; flex: none; border-radius: var(--avatar-radius); overflow: hidden; }
.forward-head .avatar-initials { font-size: 10px; }
.forward-author { font-weight: 600; font-size: 14px; color: var(--text-header); }
.forward-author:hover { text-decoration: underline; }
.forward-date { color: var(--text-muted); font-size: 12px; flex: none; }
.forward-content { font-size: 14px; color: var(--text-normal); word-wrap: break-word; }
.forward-content .mention { background: none; color: inherit; padding: 0; font-weight: 500; }
.forward-chip .msg-image img { max-width: 320px; max-height: 240px; }
.forward-chip .msg-video { max-width: 320px; }
.forward-chip .msg-sticker, .forward-chip .msg-sticker img { max-width: 120px; max-height: 120px; }
.forward-chip .msg-sticker { width: 120px; height: 120px; }

.forward-modal { width: min(100%, 440px); }
.forward-modal-body { display: flex; flex-direction: column; gap: 12px; max-height: 70vh; }
.forward-search { position: relative; display: flex; align-items: center; }
.forward-search .lucide { position: absolute; left: 10px; color: var(--text-muted); pointer-events: none; }
.forward-search .field-input { padding-left: 32px; }
.forward-list {
  max-height: 220px; overflow-y: auto; display: flex; flex-direction: column; gap: 2px;
  background: var(--bg-deepest); border-radius: var(--radius-md); padding: 6px;
}
.forward-row {
  display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
  padding: 8px 10px; border-radius: var(--radius-sm); background: none; border: 0; cursor: pointer;
  color: var(--text-normal); font-size: 14px;
}
.forward-row:hover { background: var(--bg-hover); }
.forward-row.sending { opacity: .6; cursor: default; }
.forward-row.sent { cursor: default; }
.forward-row-icon {
  width: 24px; height: 24px; display: grid; place-items: center; flex: none;
  color: var(--text-muted);
}
.forward-row-icon .avatar { width: 24px; height: 24px; border-radius: var(--avatar-radius); overflow: hidden; }
.forward-row-icon .avatar-initials { font-size: 11px; }
.forward-row-names { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.forward-row-name { font-weight: 600; color: var(--text-header); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.forward-row-server { font-size: 12px; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.forward-sent {
  display: none; align-items: center; gap: 4px; color: var(--status-online, #23a559);
  font-size: 13px; font-weight: 600; flex: none;
}
.forward-row.sent .forward-sent { display: flex; }
.forward-empty { color: var(--text-muted); font-size: 14px; text-align: center; padding: 16px 8px; }
.forward-preview {
  background: var(--bg-embed); border: 1px solid var(--bg-deepest); border-radius: var(--radius-lg);
  padding: 8px 12px 10px;
}
.forward-preview .forward-content { max-height: 120px; overflow: hidden; }
.forward-atts {
  display: flex; align-items: center; gap: 4px; color: var(--text-muted);
  font-size: 12px; margin-top: 4px;
}
.forward-comment { width: 100%; }

/* (dead .profile-note* rules removed — the live markup is .pcard-note* styled in profile.css) */

/* channel drag & drop reordering */
.channel-list { position: relative; }
.channel-item.dragging, .category-header.dragging { opacity: 0.5; }
.drop-indicator {
  position: absolute;
  left: 8px;
  right: 8px;
  height: 2px;
  background: var(--brand);
  border-radius: calc(var(--radius) * 0.25);
  pointer-events: none;
  z-index: 5;
}
.category-header.drop-into {
  background: var(--bg-hover);
  color: var(--text-header);
  box-shadow: inset 0 0 0 2px var(--brand);
  border-radius: var(--radius-sm);
}

/* muted channels/DMs/servers */
.channel-item.muted, .dm-item.muted { opacity: .45; }
.server-btn.muted { opacity: .5; }
.rail-btn.muted .rail-dot, .rail-btn.muted .rail-badge { display: none; }

/* explore: skeleton loading cards + keyboard focus */
.explore-skeleton { pointer-events: none; }
.skeleton-block {
  display: block; border-radius: var(--radius-md); position: relative; overflow: hidden;
  background: var(--bg-deep, #26272c);
}
.skeleton-block::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent 0%, rgba(255,255,255,.06) 50%, transparent 100%);
  transform: translateX(-100%);
  animation: shimmer calc(1400ms * var(--anim)) var(--ease-in-out) infinite;
}
@keyframes shimmer { to { transform: translateX(100%); } }
@media (prefers-reduced-motion: reduce) {
  .skeleton-block::after { animation: none; }
}
.skeleton-line { height: 13px; margin: 5px 0; }
.skeleton-btn { height: 32px; border-radius: var(--radius-sm); }
.explore-skeleton .explore-card-icon { border-radius: calc(var(--radius) * 3.5); }
.explore-card:focus-visible {
  outline: 2px solid var(--brand); outline-offset: 2px;
  transform: translateY(-2px); box-shadow: var(--elev-high);
}
.explore-card.joined { cursor: pointer; }
.explore-card .explore-join { cursor: pointer; }

/* threads */
.thread-bar {
  display: flex; align-items: center; gap: 8px; padding: 6px 12px;
  background: var(--bg-deep); border-bottom: 1px solid #232428;
  font-size: 13px; flex: none;
}
.thread-back {
  display: flex; align-items: center; gap: 6px; color: var(--text-muted);
  font-size: 13px; font-weight: 600; padding: 3px 8px; border-radius: var(--radius-sm);
  transition: color calc(120ms * var(--anim)) var(--ease), background-color calc(120ms * var(--anim)) var(--ease);
}
.thread-back:hover { color: var(--text-header); background: var(--bg-hover); }
.thread-bar-sep { width: 1px; height: 18px; background: var(--divider); }
.thread-bar-icon { color: var(--text-muted); }
.thread-bar-name { color: var(--text-header); font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.thread-bar-by { font-size: 12px; white-space: nowrap; }
.channel-parent { font-size: 14px; font-weight: 500; margin-left: 4px; }
.thread-modal-hint { font-size: 13px; margin: 8px 0 0; }
.threads-wrap { width: 380px; max-height: 440px; overflow-y: auto; padding: 16px; }
.threads-popover h3 { color: var(--text-header); font-size: 16px; margin: 0 0 12px; }
.thread-item {
  display: flex; align-items: center; gap: 10px; padding: 10px; border-radius: var(--radius-lg);
  background: var(--bg-deepest); margin-bottom: 8px; cursor: pointer;
  color: var(--text-muted); transition: background-color calc(120ms * var(--anim)) var(--ease);
}
.thread-item:hover { background: var(--bg-hover); }
.thread-item-body { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.thread-item-body b { color: var(--text-header); font-size: 14px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.thread-item-body .muted { font-size: 12px; }

/* empty states: server with no channel selected / channel not found */
.content-empty {
  flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 6px; padding: 48px 24px; text-align: center; color: var(--text-muted);
  min-height: 240px;
}
.server-empty-art { color: var(--bg-deep, #26272c); margin-bottom: 14px; }
.server-empty-title { color: var(--text-header); font-size: 20px; font-weight: 700; margin: 0; }
.server-empty-sub { margin: 0; font-size: 14px; line-height: 1.5; max-width: 380px; }
.server-empty-sub b { color: var(--text-normal); }

/* transient message-load failure banner (retry affordance) */
.msg-load-error {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  margin: 8px 16px; padding: 10px 14px; border-radius: var(--radius-lg);
  background: var(--bg-floating, #111214); border: 1px solid var(--border, rgba(255,255,255,0.08));
  color: var(--text-normal); font-size: 14px;
}
.msg-load-retry {
  background: var(--accent, #5865f2); color: #fff; border: 0; border-radius: var(--radius-md);
  padding: 6px 14px; font-size: 13px; font-weight: 600; cursor: pointer; white-space: nowrap;
}
.msg-load-retry:hover { filter: brightness(1.1); }
.msg-load-retry:focus-visible { outline: 2px solid var(--accent, #5865f2); outline-offset: 2px; }

/* code block: hover copy button + language chip + syntax tokens */
.codeblock.code-block { position: relative; }
.code-block .code-lang {
  position: absolute; top: 5px; right: 8px; font-size: 10px; line-height: 1;
  color: var(--text-faint); text-transform: lowercase; font-family: inherit;
  pointer-events: none; user-select: none; letter-spacing: .4px;
  transition: opacity calc(150ms * var(--anim)) var(--ease-in-out);
}
.code-block:hover .code-lang { opacity: 0; }
.code-copy {
  position: absolute; top: 5px; right: 6px; z-index: 1;
  background: #1e1f22; border: 1px solid #101214; border-radius: var(--radius-sm);
  color: var(--text-muted); font-size: 11px; font-weight: 600; line-height: 1;
  padding: 4px 8px; cursor: pointer; opacity: 0;
  transition: opacity calc(150ms * var(--anim)) var(--ease-in-out), color calc(120ms * var(--anim)) var(--ease), border-color calc(120ms * var(--anim)) var(--ease);
}
.code-block:hover .code-copy, .code-block:focus-within .code-copy, .code-copy:focus-visible { opacity: 1; }
.code-copy:hover { color: var(--text-header); border-color: #2b2d31; }
.code-copy.copied { color: #2dc770; border-color: rgba(45, 199, 112, .4); }
.codeblock .tok-kw { color: #c678dd; }
.codeblock .tok-str { color: #98c379; }
.codeblock .tok-num { color: #d19a66; }
.codeblock .tok-com { color: #5c6370; font-style: italic; }
.codeblock .tok-fn { color: #61afef; }
.codeblock .tok-attr { color: #e5c07b; }
.codeblock .tok-add { display: inline-block; width: 100%; background: rgba(46, 160, 67, .15); }
.codeblock .tok-del { display: inline-block; width: 100%; background: rgba(248, 81, 73, .15); }

/* ---- slash command popup ---- */
.slash-pop {
  position: absolute; bottom: calc(100% + 8px); left: 0; right: 0;
  background: var(--bg-floating); border-radius: var(--radius-lg); box-shadow: var(--elev-high);
  padding: 8px; z-index: 20; max-height: 320px; overflow-y: auto;
  animation: ac-in calc(120ms * var(--anim)) var(--ease);
}
.slash-title {
  color: var(--text-muted); font-size: 11px; font-weight: 700; text-transform: uppercase;
  padding: 4px 8px 8px;
}
.slash-item {
  display: flex; align-items: center; gap: 10px; padding: 7px 8px; border-radius: var(--radius-sm);
  cursor: pointer; color: var(--text-normal);
}
.slash-item.selected, .slash-item:hover { background: var(--brand); }
.slash-item.selected .slash-desc, .slash-item:hover .slash-desc { color: #ffffffb3; }
.slash-icon {
  width: 32px; height: 32px; flex: none; display: grid; place-items: center;
  background: var(--bg-deepest); border-radius: var(--radius-md);
  color: var(--text-header); font-size: 16px; font-weight: 700;
}
.slash-text { display: flex; flex-direction: column; min-width: 0; }
.slash-name { font-weight: 700; font-size: 14px; }
.slash-desc { color: var(--text-muted); font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* ---- composer character counter ---- */
.char-counter {
  position: absolute; right: 2px; bottom: -20px; z-index: 5;
  color: var(--text-muted); font-size: 12px; font-weight: 600; pointer-events: none;
}
.char-counter.over { color: var(--danger-soft); }
.char-counter.hidden { display: none; }

/* over-limit send shake */
@keyframes composer-shake {
  0%, 100% { transform: translateX(0); }
  20% { transform: translateX(-6px); }
  40% { transform: translateX(6px); }
  60% { transform: translateX(-4px); }
  80% { transform: translateX(4px); }
}
.composer.shake { animation: composer-shake calc(360ms * var(--anim)) var(--ease); }
@media (prefers-reduced-motion: reduce) {
  .composer.shake { animation: none; }
}

/* inbox popover (inbox.js) */
.inbox-pop-wrap { width: 420px; max-height: 480px; padding: 16px; overflow: hidden; display: flex; }
.inbox-pop { display: flex; flex-direction: column; min-height: 0; flex: 1; }
.inbox-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; }
.inbox-head h3 { color: var(--text-header); font-size: 16px; margin: 0; }
.inbox-markall { color: var(--text-muted); font-size: 12px; font-weight: 600; padding: 4px 8px; border-radius: var(--radius-sm); transition: color calc(120ms * var(--anim)) var(--ease), background-color calc(120ms * var(--anim)) var(--ease); }
.inbox-markall:hover:not(:disabled) { color: var(--text-header); background: var(--bg-hover); }
.inbox-markall:disabled { opacity: .5; cursor: default; }
.inbox-list { overflow-y: auto; min-height: 0; display: flex; flex-direction: column; gap: 2px; }
.inbox-title-row { display: flex; align-items: baseline; gap: 8px; min-width: 0; }
.inbox-title-row b { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.inbox-server { font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; flex: none; max-width: 40%; }
.inbox-preview { font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.inbox-glyph { display: flex; align-items: center; justify-content: center; width: 32px; height: 32px; border-radius: 50%; background: var(--bg-deepest); flex: none; }
.inbox-badge-mention { flex: none; }
.inbox-empty { display: flex; flex-direction: column; align-items: center; gap: 8px; padding: 32px 0; }
.inbox-empty .muted { margin: 0; font-size: 14px; }

/* keyboard shortcut cheat sheet (shortcuts.js) */
.shortcut-sheet { padding: 20px; min-width: 440px; }
.shortcut-sheet h3 { color: var(--text-header); font-size: 16px; margin: 0 0 16px; }
.shortcut-cols { display: grid; grid-template-columns: 1fr 1fr; gap: 8px 24px; }
.shortcut-row { display: flex; align-items: center; gap: 10px; padding: 6px 0; }
.shortcut-keys { flex: none; display: flex; gap: 3px; }
.shortcut-desc { color: var(--text-muted); font-size: 13px; }

/* ============ pins popover (Discord parity) ============ */
.pins-popover h3 { display: flex; align-items: center; gap: 8px; }
.pins-h-icon { color: var(--text-muted); }
.pins-list { display: flex; flex-direction: column; gap: 8px; }
.pin-card {
  position: relative; display: flex; flex-direction: column; gap: 6px;
  background: var(--bg-deepest); border: 1px solid transparent; border-radius: var(--radius-lg);
  padding: 10px 12px; cursor: pointer; transition: background-color calc(120ms * var(--anim)) var(--ease), border-color calc(120ms * var(--anim)) var(--ease);
}
.pin-card:hover { background: var(--bg-hover); border-color: var(--divider); }
.pin-card:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }
.pin-card-head { display: flex; align-items: center; gap: 8px; min-width: 0; }
.pin-card-head .avatar, .pin-card-head img { flex: none; border-radius: var(--avatar-radius); }
.pin-card-author { color: var(--text-header); font-weight: 600; font-size: 14px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pin-card-ts { color: var(--text-faint); font-size: 12px; flex: none; margin-left: 2px; }
.pin-unpin {
  margin-left: auto; flex: none; width: 24px; height: 24px; padding: 0;
  display: grid; place-items: center; color: var(--text-muted);
  opacity: 0; transition: opacity calc(120ms * var(--anim)) var(--ease);
}
.pin-card:hover .pin-unpin, .pin-card:focus-within .pin-unpin { opacity: 1; }
.pin-unpin:hover { color: var(--text-header); background: var(--bg-active); }
.pin-card-body { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.pin-card-text {
  color: var(--text-normal); font-size: 14px; line-height: 1.4;
  display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical;
  overflow: hidden; word-wrap: break-word;
}
.pin-card-text pre, .pin-card-text blockquote { margin: 4px 0; }
.pin-card-thumbs { display: flex; gap: 6px; flex-wrap: wrap; }
.pin-thumb {
  max-width: 96px; max-height: 96px; border-radius: var(--radius-sm); object-fit: cover;
  border: 1px solid var(--divider);
}
.pins-empty {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 12px; padding: 32px 16px; text-align: center; color: var(--text-muted);
}
.pins-empty-art {
  width: 72px; height: 72px; border-radius: 50%; background: var(--bg-deep);
  display: grid; place-items: center; color: var(--text-faint);
}
.pins-empty p { margin: 0; font-size: 14px; }

/* ============ message link preview tooltip ============ */
.msg-link-preview {
  position: fixed; z-index: 1000; background: var(--bg-floating);
  border: 1px solid #1f2023; border-radius: var(--radius-lg); padding: 10px 12px;
  box-shadow: 0 8px 24px rgba(0,0,0,.4); max-width: 400px;
  display: flex; flex-direction: column; gap: 6px;
  color: var(--text-normal); font-size: 14px; line-height: 1.35;
  pointer-events: none; /* hover lives on the anchor; preview is informational */
}
.mlp-head { display: flex; align-items: center; gap: 6px; min-width: 0; }
.mlp-head .avatar, .mlp-head img { flex: none; border-radius: var(--avatar-radius); }
.mlp-author { color: var(--text-header); font-weight: 600; font-size: 13px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.mlp-ts { color: var(--text-faint); font-size: 11px; flex: none; }
.mlp-body {
  color: var(--text-normal); word-wrap: break-word; overflow-wrap: anywhere;
}
.mlp-foot { font-size: 11px; color: var(--text-faint); }
.mlp-loading, .mlp-err { color: var(--text-muted); font-size: 13px; padding: 4px 0; }

/* ============ jump bars (jumpbar.js): viewing-older + jump-to-present arrow ============ */
/* bars are appended to .chat-area (position:relative) and float over the
   scroller's visible rect; top/bottom offsets are set inline by jumpbar.js */
.message-scroller { position: relative; }
.jump-top, .jump-bottom {
  position: absolute; left: 16px; right: 16px; z-index: 7;
  display: flex; align-items: center; gap: 8px;
  border-radius: var(--radius-lg); box-shadow: var(--shadow-elev);
  font-size: 13px; line-height: 1.3;
  opacity: 0; pointer-events: none;
  transition: opacity calc(160ms * var(--anim)) var(--ease), transform calc(160ms * var(--anim)) var(--ease);
}
.jump-top { transform: translateY(-8px); background: var(--bg-floating); padding: 8px 12px; color: var(--text-normal); }
.jump-bottom {
  left: auto; right: 16px;
  width: 40px; height: 40px; padding: 0; justify-content: center;
  border-radius: 50%;
  transform: translateY(8px); background: var(--bg-active); color: var(--text-header);
  cursor: pointer; border: none;
}
.jump-top.visible, .jump-bottom.visible { opacity: 1; pointer-events: auto; transform: translateY(0); }
.jump-top-label { flex: 1; min-width: 0; color: var(--text-muted); }
.jump-top-btn {
  background: var(--brand); color: #fff; font-weight: 600; font-size: 13px;
  border-radius: var(--radius-md); padding: 6px 12px; flex: none;
}
.jump-top-btn:hover { background: var(--brand-hover); }
.jump-top-btn:active { background: var(--brand-active); }
.jump-bottom:hover { background: var(--bg-active); filter: brightness(1.15); color: var(--text-header); }
.jump-bottom-arrow { flex: none; }
@media (prefers-reduced-motion: reduce) {
  .jump-top, .jump-bottom { transition: none; transform: none; }
}

/* ---- gifpicker.js (local GIF/animated-sticker picker) ---- */
.gifpicker-scroll { min-height: 0; }
.gifpicker-cell { position: relative; }
.gifpicker-name {
  position: absolute; left: 6px; bottom: 4px; right: 6px;
  font-size: 11px; font-weight: 600; color: var(--text-header, #fff);
  text-shadow: 0 1px 2px rgba(0,0,0,.6);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  opacity: 0; transition: opacity calc(120ms * var(--anim)) var(--ease); pointer-events: none;
}
.gifpicker-cell:hover .gifpicker-name, .gifpicker-cell:focus-visible .gifpicker-name { opacity: 1; }

/* ---- og.js (frontend link-preview cards) ---- */
.link-embed {
  border-left: 4px solid var(--bg-deepest);
  background: var(--bg-embed);
  border-radius: var(--radius-sm);
  padding: 10px 12px;
  margin-top: 4px;
  max-width: 400px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.link-embed-main { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.link-embed-site {
  display: flex; align-items: center; gap: 6px;
  color: var(--text-muted); font-size: 12px; line-height: 1.2;
}
.link-embed-favicon { width: 16px; height: 16px; border-radius: calc(var(--radius) * 0.75); flex: none; }
.link-embed-title {
  color: var(--link); font-weight: 600; font-size: 15px; line-height: 1.3;
  overflow-wrap: anywhere;
}
.link-embed-title:hover { text-decoration: underline; }
.link-embed-desc {
  color: var(--text-normal); font-size: 13px; line-height: 1.4;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
.link-embed-image {
  max-width: 100%; max-height: 260px; width: auto;
  border-radius: var(--radius-lg); margin-top: 2px; object-fit: contain;
}
/* when the server knows the image dimensions we reserve the box up front, so a
   resolving preview doesn't reflow the message column */
.link-embed-image.has-ar { width: 100%; height: auto; }

/* ---- quick switcher Discord parity (quickswitch.js) ---- */
/* channel "#" glyph — muted, inherits selected state like the label */
.qs-hash {
  width: 24px; flex: none; text-align: center; color: var(--text-muted);
  font-size: 18px; font-weight: 600; display: inline-flex; justify-content: center; align-items: center;
}
.qs-item.selected .qs-hash { color: var(--text-header); }
/* server initial tile (mini rail button) */
.qs-server-tile {
  width: 24px; height: 24px; flex: none; border-radius: var(--radius-md); overflow: hidden;
  display: inline-flex; align-items: center; justify-content: center;
  color: #fff; font-size: 10px; font-weight: 700; letter-spacing: .02em;
  background: var(--bg-hover);
}
.qs-server-tile img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* DM / user avatars at 24px */
.qs-avatar { width: 24px; height: 24px; flex: none; display: inline-flex; }
.qs-avatar .avatar { width: 24px !important; height: 24px !important; font-size: 10px; }
.qs-avatar.qs-group {
  border-radius: 50%; background: var(--bg-hover); color: var(--text-muted);
  align-items: center; justify-content: center;
}
.qs-item.selected .qs-avatar.qs-group { color: var(--text-header); }
/* empty state — muted magnifier over "No results found" */
.qs-empty { display: flex; flex-direction: column; align-items: center; gap: 8px; padding: 28px 20px; }
.qs-empty-icon { color: var(--text-faint); opacity: .8; }
/* matched substring: bold white inside the muted result name */
.qs-label mark { color: #fff; font-weight: 700; }
.qs-item.selected .qs-label mark { color: #fff; }
/* footer kbd chips */
.qs-footer kbd {
  background: var(--bg-hover); border: 1px solid var(--border, rgba(255,255,255,.08));
  border-radius: calc(var(--radius) * 0.75); padding: 1px 5px; font-size: 11px; font-family: inherit; color: var(--text-normal);
}

/* roles settings two-pane layout */
.roles-layout { display: grid; grid-template-columns: 220px 1fr; gap: 24px; align-items: start; }
.roles-side { display: flex; flex-direction: column; gap: 10px; }
.primary-btn.block { width: 100%; }
.roles-side-list { margin-bottom: 0; max-height: 480px; overflow-y: auto; }
.role-row.active { outline: 2px solid var(--brand); outline-offset: -2px; }
.role-row.clickable { cursor: pointer; }
.role-row.clickable:hover { background: var(--bg-hover); }
.roles-editor {
  background: var(--bg-deepest); border-radius: var(--radius-lg); padding: 16px;
  display: flex; flex-direction: column; gap: 14px; min-width: 0;
}
.roles-placeholder { margin: 24px 0; text-align: center; }
.role-editor-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.color-input.small { width: 44px; height: 30px; }
.perm-list { display: flex; flex-direction: column; }
.perm-row {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 10px 0; border-bottom: 1px solid var(--divider); cursor: pointer;
}
.perm-row:last-child { border-bottom: 0; }
.perm-text { display: flex; flex-direction: column; gap: 2px; color: var(--text-header); }
.perm-text .muted { font-weight: 400; }
.perm-row input[type="checkbox"] { flex: none; width: 18px; height: 18px; accent-color: var(--brand); cursor: pointer; }
.role-editor-actions { display: flex; justify-content: space-between; align-items: center; margin-top: 6px; }
.radio-row.publish-row { align-items: flex-start; margin: 4px 0 8px; max-width: 520px; }
.radio-row.publish-row input[type="checkbox"] { margin-top: 3px; width: 18px; height: 18px; accent-color: var(--brand); }

/* ---- a11y.js: skip link + focus-visible pass ---- */

/* Skip link: visually hidden until focused, then a brand chip top-left. */
.skip-link {
  position: fixed; top: -48px; left: 8px; z-index: 4000;
  padding: 8px 14px; border-radius: var(--radius-md);
  background: var(--brand); color: #fff; font-size: 14px; font-weight: 600;
  text-decoration: none;
  opacity: 0; pointer-events: none;
  transition: top calc(150ms * var(--anim)) var(--ease), opacity calc(150ms * var(--anim)) var(--ease);
}
.skip-link:focus-visible {
  top: 8px; opacity: 1; pointer-events: auto;
  outline: 2px solid #fff; outline-offset: 2px;
}

/* Keyboard focus ring: single tasteful outline, keyboard-only via :focus-visible. */
button:focus-visible,
.rail-btn:focus-visible,
.channel-item:focus-visible,
.dm-item:focus-visible,
.friend-row:focus-visible,
.ctx-item:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
[contenteditable="true"]:focus-visible,
a[href]:focus-visible,
[role="button"]:focus-visible,
.settings-nav-item:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 1px;
  border-radius: inherit;
}

/* The ring is --brand, which is invisible on controls already filled with the
   accent (or red/green). Use a neutral ring there so keyboard focus is visible. */
.primary-btn:focus-visible,
.danger-btn:focus-visible,
.friends-tab.add-tab:focus-visible,
.inbox-tab.active:focus-visible,
.rail-btn.active:focus-visible {
  outline-color: #fff;
  outline-offset: 2px;
}

/* Inputs that already restyle on :focus (border color) still get the ring on
   keyboard focus only — :focus-visible never fires on mouse click, so the
   composer/field mouse affordances are untouched. */

/* The composer keeps its :focus-within affordance; the ring stacks fine. */
.composer:focus-within .composer-input:focus-visible { outline: none; }

/* typing indicator — Discord text uses <strong> for usernames; the bar already
   styles <b>, keep both selectors in sync. */
.typing-bar strong { color: var(--text-header); }

/* typing dots: honor reduced-motion — dots stay visible but static. */
@media (prefers-reduced-motion: reduce) {
  .typing-dots i { animation: none; opacity: .8; }
}

/* presence dots: fade status changes instead of snapping (200ms, Discord-like). */
.avatar-status, .status-dot { transition: background-color calc(200ms * var(--anim)) var(--ease); }

/* ---- hover action bar polish ----
   Discord-parity overrides: the bar floats above the message's top-right
   corner; here we deepen the surface (elevated floating bg), round to 8px,
   pad 4px, and add a stronger elevation shadow. Buttons keep their 32px
   square hit area and gain a press animation. */
.msg-row .msg-hover-actions {
  background: var(--bg-floating);
  border: 1px solid rgba(255, 255, 255, .06);
  border-radius: var(--radius-lg);
  padding: 4px;
  gap: 2px;
  box-shadow: 0 8px 16px rgba(0, 0, 0, .36), 0 2px 4px rgba(0, 0, 0, .24);
}
.msg-row .msg-hover-actions .icon-btn {
  border-radius: var(--radius-sm);
  transition: transform calc(80ms * var(--anim)) var(--ease), color calc(100ms * var(--anim)) var(--ease), background-color calc(100ms * var(--anim)) var(--ease);
}
.msg-row .msg-hover-actions .icon-btn:hover {
  color: var(--text-normal);
  background: var(--bg-hover);
}
.msg-row .msg-hover-actions .icon-btn:active {
  transform: scale(.95);
  transition-duration: 80ms;
}

/* ---- reaction chip polish ----
   Mine vs not-mine is handled by the base rules (brand-tinted bg + brand
   border for .mine, neutral otherwise). These overrides brighten the border
   and bolden the count on hover, and add the one-time .just-added burst when
   you add a reaction yourself. */
.msg-row .reaction:hover {
  border-color: var(--text-muted);
  background: rgba(78, 80, 88, .45);
}
.msg-row .reaction.mine:hover {
  border-color: var(--brand-hover);
  background: rgba(88, 101, 242, .26);
}
.msg-row .reaction:hover .reaction-count {
  color: var(--text-header);
  font-weight: 700;
}
@keyframes reaction-just-added {
  0% { transform: scale(1); }
  45% { transform: scale(1.15); }
  100% { transform: scale(1); }
}
.reaction.just-added {
  animation: reaction-just-added calc(300ms * var(--anim)) var(--ease);
}
@media (prefers-reduced-motion: reduce) {
  .reaction.just-added { animation: none; }
}

/* Perf: skip rendering of off-screen message groups in long channels.
   contain-intrinsic-size reserves an estimated height so the scrollbar
   stays sane before the group is first rendered. Verified via headless
   chromium: scrollHeight constant and scroll positions symmetric
   scrolling up/down with 150 rows across multiple groups.
   containment only applies while a group is off-screen, so its on-screen
   descendants (`.msg-hover-actions`, `.msg-gutter-time`) are never clipped.
   72px (not 40px) is a realistic single-group height, which keeps the estimated
   scroll offset closer to the real one so jump-to-message lands accurately. */
.msg-group {
  content-visibility: auto;
  contain-intrinsic-size: auto 72px;
}

/* ============ invite landing (invite.js) ============ */
.invite-overlay {
  position: fixed; inset: 0; z-index: 400;
  display: grid; place-items: center; overflow: hidden;
}
.invite-overlay .auth-bg { position: absolute; inset: 0; }
.invite-card {
  grid-template-columns: 1fr; width: min(92vw, 420px);
  text-align: center; padding: 32px 28px;
}
.invite-col { display: flex; flex-direction: column; align-items: center; }
.invite-loading { display: grid; place-items: center; min-height: 220px; }
.invite-server-icon-wrap { margin-bottom: 18px; }
.invite-server-icon {
  width: 72px; height: 72px; border-radius: calc(var(--radius) * 5); object-fit: cover;
  display: inline-grid; place-items: center;
}
.invite-server-initials {
  background: var(--brand); color: #fff; font-size: 24px; font-weight: 700;
  letter-spacing: .5px;
}
.invite-invalid-icon { background: var(--bg-deepest); color: var(--text-muted); }
.invite-eyebrow {
  color: var(--text-muted); font-size: 11.5px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .8px; margin: 0 0 6px;
}
.invite-server-name {
  color: var(--text-header); font-size: 22px; font-weight: 800;
  margin: 0 0 10px; overflow-wrap: anywhere;
}
.invite-stats {
  display: flex; align-items: center; justify-content: center; gap: 14px;
  min-height: 18px; margin-bottom: 20px;
}
.invite-stat {
  display: inline-flex; align-items: center; gap: 6px;
  color: var(--text-muted); font-size: 13.5px; font-weight: 500;
}
.invite-online-dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--green); display: inline-block; flex: none;
}
.invite-accept { width: 100%; }
.invite-card .auth-error { text-align: center; }
.invite-invalid-sub {
  color: var(--text-muted); font-size: 14px; line-height: 1.5;
  margin: 0 0 20px;
}
.invite-login-note {
  position: absolute; top: 20px; left: 50%; transform: translateX(-50%);
  display: flex; align-items: center; gap: 8px;
  background: var(--bg-floating); color: var(--text-normal);
  border-radius: var(--radius-lg); padding: 10px 16px; font-size: 14px;
  box-shadow: var(--elev-high); animation: auth-in calc(300ms * var(--anim)) var(--ease-out);
  max-width: 92vw;
}
.invite-login-note .lucide { color: var(--brand); flex: none; }
@media (prefers-reduced-motion: reduce) {
  .invite-login-note { animation: none; }
}

/* ---- member list presence polish (presence.js) ---- */

/* Custom status tooltip support: ellipsis already applied via .member-custom;
   ensure the span never forces the row wider than the list and that the
   title-tooltip variant clips cleanly too. */
.member-item .member-custom {
  display: block;
  max-width: 100%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.member-item .member-name {
  min-width: 0;
}

@media (prefers-reduced-motion: no-preference) {
  /* Entry: new member rows fade + slide in from the left. Applied by
     presence.js only to member items whose data-user id was not present in
     the previous render snapshot (wholesale innerHTML renders re-add every
     node, so without diffing the whole list would animate each time). */
  @keyframes member-enter {
    from { opacity: 0; transform: translateX(-8px); }
    to   { opacity: 1; transform: translateX(0); }
  }
  .member-item.member-enter {
    animation: member-enter calc(150ms * var(--anim)) var(--ease-out) both;
  }
  /* Offline members dim via opacity; keep the enter animation's final
     state from fighting the .offline opacity by animating a custom prop. */
  .member-item.member-enter.offline {
    animation-name: member-enter-offline;
  }
  @keyframes member-enter-offline {
    from { opacity: 0; transform: translateX(-8px); }
    to   { opacity: .4; transform: translateX(0); }
  }

  /* Status flip: brief scale pulse on the presence dot when a member's
     status class changes between renders (offline -> online etc.). */
  @keyframes status-pulse {
    0%   { transform: scale(1); }
    40%  { transform: scale(1.4); }
    100% { transform: scale(1); }
  }
  .avatar-status.status-pulse {
    animation: status-pulse calc(250ms * var(--anim)) var(--ease-in-out) both;
  }
}

/* ---------------- Group DM settings popover (gdm.js) ---------------- */
.gdm-wrap { width: 340px; max-height: 480px; overflow-y: auto; padding: 16px; --status-ring: var(--bg-floating); }
.gdm-popover h3 { display: flex; align-items: center; gap: 8px; color: var(--text-header); font-size: 16px; margin: 0 0 12px; }
.gdm-field { margin-bottom: 14px; }
.gdm-section-label { color: var(--text-faint); font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .02em; margin: 4px 0 8px; }
.gdm-member-list { display: flex; flex-direction: column; gap: 2px; max-height: 220px; overflow-y: auto; margin-bottom: 14px; }
.gdm-member { display: flex; align-items: center; gap: 10px; padding: 6px 8px; border-radius: var(--radius-md); }
.gdm-member:hover { background: var(--bg-hover); }
.gdm-member-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 14px; }
.gdm-owner-tag { background: var(--brand); color: #fff; font-size: 10px; font-weight: 700; text-transform: uppercase; border-radius: var(--radius-sm); padding: 2px 5px; }
.gdm-footer { border-top: 1px solid var(--border, rgba(255,255,255,.08)); padding-top: 12px; }
.danger-btn.gdm-wide { width: 100%; }

/* Group DM settings: icon row + add/remove members (gdm.js) */
.gdm-icon-row { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; }
.gdm-icon-btn { position: relative; width: 56px; height: 56px; border-radius: 50%; border: 1px dashed var(--border, rgba(255,255,255,.12)); background: var(--bg-embed); color: var(--text-muted); cursor: pointer; display: grid; place-items: center; flex: none; transition: border-color calc(150ms * var(--anim)) var(--ease), color calc(150ms * var(--anim)) var(--ease); }
.gdm-icon-btn:hover { border-color: var(--brand); color: var(--text-header); }
.gdm-icon-btn img { width: 100%; height: 100%; object-fit: cover; border-radius: 50%; }
.gdm-icon-edit { position: absolute; right: -2px; bottom: -2px; width: 20px; height: 20px; border-radius: 50%; background: var(--brand); color: #fff; display: grid; place-items: center; box-shadow: 0 1px 4px rgba(0,0,0,.4); }
.gdm-icon-hint { font-size: 12px; line-height: 1.35; color: var(--text-normal); }
.gdm-add-list { max-height: 160px; overflow-y: auto; margin-bottom: 4px; }
.gdm-member .gdm-add, .gdm-member .gdm-remove { opacity: 0; width: 26px; height: 26px; margin-left: auto; transition: opacity calc(120ms * var(--anim)) var(--ease), background calc(120ms * var(--anim)) var(--ease); }
.gdm-member:hover .gdm-add, .gdm-member:hover .gdm-remove { opacity: 1; }
.gdm-member .gdm-add:hover { background: rgba(35,165,90,.25); color: #23a55a; }
.gdm-member .gdm-remove:hover { background: rgba(218,55,60,.25); color: #da373c; }
.gdm-addable .gdm-add { opacity: 1; }

/* gdm popover: name must flex, trailing controls fixed so they never wrap */
.gdm-member .gdm-add, .gdm-member .gdm-remove { flex: none; margin-left: 0; }
.gdm-member-name { flex: 1 1 auto; }

/* ---------------- badge fidelity pass (audit) ---------------- */
/* Discord unread server indicator is a white pill on the LEFT EDGE of the rail
   (4px wide, 8px tall, vertically centered) — the same geometry as the hover/
   active ::before pill — not a circle dot in the bottom corner. The JS renders
   <span class="rail-dot"> for unread-without-mention; restyle it in place. */
.rail-dot {
  left: -12px; right: auto; top: 50%; bottom: auto;
  transform: translateY(-50%);
  width: 4px; height: 8px; border-radius: 0 var(--radius-xs) var(--radius-xs) 0;
  background: var(--text-header); box-shadow: none;
}

/* Mention badges use Discord's notification red #f23f43, which is distinct
   from the danger-button red (--red). */
.badge { background: var(--red-badge); }
.rail-badge { background: var(--red-badge); }
/* Rail mention badge: Discord keeps these compact (16px tall, 8px radius pill). */
.rail-badge {
  min-width: 16px; height: 16px; border-radius: var(--radius-lg);
  font-size: 11px; font-weight: 700; padding: 0 4px;
  box-shadow: 0 0 0 3px var(--bg-deepest);
}

/* "NEW" unread divider: 1px red line + right-aligned red caps label. */
.msg-new { color: var(--red-badge); }
.msg-new::before { background: var(--red-badge); }

/* Typing indicator: Discord's bar is 24px tall, transparent bg, NOT italic;
   names bold white, the rest muted; dots #b5bac1. */
.typing-bar {
  height: 24px; background: transparent; font-style: normal;
  color: var(--text-muted);
}
.typing-bar strong, .typing-bar b { color: var(--text-header); }
.typing-dots i { background: #b5bac1; }

/* ============================================================
   Message markup extensions: tables, to-do lists, charts
   ============================================================ */
.md-table-wrap { max-width: 100%; overflow-x: auto; margin: 6px 0; border-radius: var(--radius-md); border: 1px solid var(--bg-deepest); }
.md-table { border-collapse: collapse; min-width: 50%; font-size: 14px; }
.md-table th, .md-table td { border: 1px solid var(--divider); padding: 6px 12px; text-align: left; }
.md-table th { background: var(--bg-deep); color: var(--text-header); font-weight: 700; }
.md-table tr:nth-child(even) td { background: rgba(255,255,255,.02); }
.md-todo-list { list-style: none; padding-left: 4px; }
.md-todo { display: flex; gap: 8px; align-items: flex-start; }
.md-todo-box {
  width: 18px; height: 18px; border-radius: var(--radius-sm); border: 2px solid var(--text-faint);
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  font-size: 13px; color: #fff; margin-top: 2px;
}
.md-todo.done .md-todo-box { background: var(--brand); border-color: var(--brand); }
.md-todo.done .md-todo-text { color: var(--text-muted); text-decoration: line-through; }
.md-chart {
  background: var(--bg-deep); border: 1px solid var(--bg-deepest); border-radius: var(--radius-lg);
  padding: 8px 10px 4px; margin: 6px 0; max-width: 420px;
}
.md-chart-head { display: flex; align-items: center; gap: 6px; color: var(--text-muted); font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: .02em; margin-bottom: 4px; }
/* Scoped to .md-chart so this beats the generic `.md-chart svg { width:100% }`
   below (equal specificity, later rule would otherwise stretch the header icon
   to the full chart width — the "enormous header" bug). */
.md-chart .md-chart-head svg { width: 14px; height: 14px; flex: none; }
.md-chart > svg { width: 100%; height: auto; }
.md-chart-error { color: var(--red); font-size: 13px; }

/* ============================================================
   Interactive bot components
   ============================================================ */
.msg-components { display: flex; flex-direction: column; gap: 6px; margin-top: 6px; max-width: 560px; }
.cmp-row { display: flex; flex-wrap: wrap; gap: 8px; align-items: stretch; }
.cmp-btn {
  display: inline-flex; align-items: center; gap: 6px; padding: 7px 14px; border-radius: var(--radius-sm);
  font-size: 14px; font-weight: 600; background: var(--bg-active); color: var(--text-header);
  border: 1px solid transparent; transition: background-color calc(120ms * var(--anim)) var(--ease), opacity calc(120ms * var(--anim)) var(--ease);
}
.cmp-btn:hover { background: var(--bg-hover); }
.cmp-btn:disabled { opacity: .5; cursor: not-allowed; }
.cmp-primary { background: var(--brand); color: #fff; }
.cmp-primary:hover { background: var(--brand-hover); }
.cmp-success { background: var(--green); color: #fff; }
.cmp-danger { background: var(--red); color: #fff; }
.cmp-link { background: transparent; color: var(--link); padding-left: 2px; }
.cmp-emoji { font-size: 16px; line-height: 1; }
.cmp-emoji.emoji { width: 18px; height: 18px; }
.cmp-select {
  background: var(--bg-input); color: var(--text-header); border: 1px solid var(--bg-deepest);
  border-radius: var(--radius-sm); padding: 8px 10px; font-size: 14px; min-width: min(200px, 100%); max-width: 100%;
}
.cmp-select.cmp-submitted { opacity: .6; }
.cmp-form { display: flex; flex-direction: column; gap: 8px; background: var(--bg-deep); border: 1px solid var(--bg-deepest); border-radius: var(--radius-lg); padding: 12px; }
.cmp-field { display: flex; flex-direction: column; gap: 4px; }
.cmp-field-label { font-size: 12px; font-weight: 700; color: var(--text-muted); text-transform: uppercase; letter-spacing: .02em; }
.cmp-input { background: var(--bg-input); border: 1px solid var(--bg-deepest); border-radius: var(--radius-sm); padding: 8px 10px; color: var(--text-header); font-size: 14px; resize: vertical; }
.cmp-form.cmp-submitted { opacity: .7; }
.cmp-submit { align-self: flex-start; margin-top: 2px; }

/* ============================================================
   Forgejo rich previews
   ============================================================ */
.fj-embed {
  display: block; max-width: 440px; margin-top: 6px; padding: 10px 12px;
  background: var(--bg-embed); border-left: 4px solid var(--brand); border-radius: var(--radius-sm);
  color: var(--text-normal); text-decoration: none;
}
.fj-embed:hover { text-decoration: none; background: var(--bg-hover); }
.fj-head { display: flex; align-items: center; gap: 6px; font-size: 13px; flex-wrap: wrap; }
.fj-avatar { width: 22px; height: 22px; border-radius: 50%; object-fit: cover; }
.fj-owner, .fj-repo-path { color: var(--text-muted); }
.fj-repo, .fj-repo-path b { color: var(--text-header); }
.fj-slash { color: var(--text-faint); }
.fj-number { color: var(--text-muted); font-weight: 600; }
.fj-title { color: var(--text-header); font-weight: 600; margin-top: 4px; overflow-wrap: anywhere; }
.fj-desc { color: var(--text-normal); font-size: 13px; margin-top: 4px; }
.fj-sub { color: var(--text-muted); font-size: 12px; margin-top: 3px; }
.fj-meta { display: flex; gap: 12px; margin-top: 6px; color: var(--text-muted); font-size: 12px; }
.fj-lang-dot { display: inline-block; width: 9px; height: 9px; border-radius: 50%; background: var(--yellow); margin-right: 4px; }
.fj-add { color: var(--status-online); } .fj-del { color: var(--red); }
.fj-sha { font-size: 12px; color: var(--text-muted); background: var(--bg-deepest); padding: 1px 5px; border-radius: var(--radius-sm); }
.fj-labels { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 6px; }
.fj-label { font-size: 11px; font-weight: 600; padding: 1px 7px; border-radius: 999px; color: var(--lc, var(--text-normal)); border: 1px solid var(--lc, #5865f2); background: color-mix(in srgb, var(--lc, #5865f2) 16%, transparent); }
.fj-topics { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 6px; }
.fj-topic { font-size: 11px; color: var(--link); background: color-mix(in srgb, var(--link) 12%, transparent); padding: 1px 7px; border-radius: 999px; }
.fj-state { display: inline-flex; align-items: center; gap: 4px; font-size: 12px; font-weight: 600; color: var(--text-muted); }
.fj-state.open { color: var(--status-online); }
.fj-state.closed { color: var(--red); }
.fj-state.merged { color: #a371f7; }
.fj-glyph { display: inline-flex; align-items: center; justify-content: center; font-size: 16px; }

/* ============================================================
   Economy (Aura + AMM tokens)
   ============================================================ */
.aura-balance-card { display: flex; align-items: center; justify-content: space-between; gap: 16px; background: var(--bg-deepest); border: 1px solid var(--bg-hover); border-radius: var(--radius-xl); padding: 16px; margin: 12px 0; }
.aura-balance { display: flex; align-items: center; gap: 8px; font-size: 26px; color: var(--text-header); }
.aura-glyph { color: var(--yellow); display: inline-flex; }
.holdings-list, .token-list, .lb-list, .tx-list { display: flex; flex-direction: column; gap: 4px; margin-top: 8px; }
.holding-row, .token-row { display: flex; align-items: center; gap: 12px; width: 100%; text-align: left; padding: 10px 12px; border-radius: var(--radius-md); background: var(--bg-deepest); border: 1px solid transparent; }
.holding-row:hover, .token-row:hover { background: var(--bg-hover); }
.token-avatar { width: 34px; height: 34px; border-radius: 50%; background: var(--tc, var(--brand)); color: #fff; font-weight: 800; font-size: 12px; display: inline-flex; align-items: center; justify-content: center; flex: none; }
.token-avatar.big { width: 52px; height: 52px; font-size: 16px; }
.holding-name, .token-info { display: flex; flex-direction: column; flex: 1; min-width: 0; }
.holding-amount, .token-price { display: flex; flex-direction: column; align-items: flex-end; }
.token-own { color: var(--yellow); font-weight: 700; font-size: 13px; }
.transfer-row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.transfer-row .field-input { flex: 1; min-width: 120px; }
.lb-row { display: flex; align-items: center; gap: 12px; padding: 8px 12px; border-radius: var(--radius-md); }
.lb-row.me { background: rgba(88,101,242,.15); }
.lb-rank { width: 28px; text-align: center; font-weight: 700; color: var(--text-muted); }
.lb-name { flex: 1; color: var(--text-header); }
.lb-aura { color: var(--yellow); font-weight: 700; display: inline-flex; align-items: center; gap: 4px; }
.tx-row { display: flex; align-items: center; gap: 10px; padding: 7px 10px; border-radius: var(--radius-md); background: var(--bg-deepest); }
.tx-kind { font-size: 10px; font-weight: 800; text-transform: uppercase; letter-spacing: .04em; padding: 2px 7px; border-radius: var(--radius-sm); background: var(--bg-active); color: var(--text-muted); }
.tx-kind.k-buy, .tx-kind.k-faucet, .tx-kind.k-work, .tx-kind.k-daily, .tx-kind.k-crime, .tx-kind.k-gamble, .tx-kind.k-yield { background: rgba(35,165,90,.18); color: var(--status-online); }
.tx-kind.k-sell, .tx-kind.k-stake, .tx-kind.k-trade, .tx-kind.k-transfer, .tx-kind.k-unstake { background: rgba(218,55,60,.18); color: var(--red); }
.tx-kind.k-mint { background: rgba(240,178,50,.18); color: var(--yellow); }
.tx-main { flex: 1; display: flex; flex-direction: column; min-width: 0; }
.tx-time { flex: none; }
.td-head { display: flex; align-items: center; gap: 12px; }
.td-stats { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; margin: 16px 0; }
.td-stat { background: var(--bg-deepest); border-radius: var(--radius-lg); padding: 10px 12px; display: flex; flex-direction: column; gap: 2px; }
.td-stat b { color: var(--text-header); font-size: 16px; }
.td-trade { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.trade-col { display: flex; flex-direction: column; gap: 6px; background: var(--bg-deepest); border-radius: var(--radius-lg); padding: 12px; }
.trade-input-row { display: flex; gap: 6px; }
.trade-input-row .field-input { flex: 1; min-width: 0; }
@media (max-width: 560px) { .td-trade, .td-stats { grid-template-columns: 1fr; } }

/* ============================================================
   AI assistant
   ============================================================ */
.ai-chat { display: flex; flex-direction: column; gap: 10px; max-height: 46vh; overflow-y: auto; padding: 8px 2px; margin: 12px 0; }
.ai-empty { color: var(--text-muted); font-size: 13px; text-align: center; padding: 24px; }
.ai-bubble { max-width: 88%; padding: 10px 12px; border-radius: var(--radius-xl); font-size: 14px; overflow-wrap: anywhere; }
.ai-user { align-self: flex-end; background: var(--brand); color: #fff; }
.ai-bot { align-self: flex-start; background: var(--bg-deepest); color: var(--text-normal); }
.ai-bot.pending { display: inline-flex; align-items: center; gap: 8px; color: var(--text-muted); }
.ai-error { align-self: flex-start; color: var(--red); font-size: 13px; }
.ai-composer { display: flex; gap: 8px; align-items: flex-end; }
.ai-composer textarea { flex: 1; resize: vertical; }
.ai-prompt-row { display: flex; gap: 8px; align-items: center; }
.ai-prompt-row .field-input { flex: 1; }
.ai-loading { display: flex; align-items: center; gap: 8px; color: var(--text-muted); margin: 12px 0; }
.theme-actions { display: flex; gap: 10px; align-items: center; margin: 10px 0; }
.theme-list { display: flex; flex-direction: column; gap: 4px; }
.theme-row { display: flex; align-items: center; gap: 10px; padding: 8px 10px; background: var(--bg-deepest); border-radius: var(--radius-md); }
.theme-swatch { width: 20px; height: 20px; border-radius: calc(var(--radius) * 1.25); flex: none; }
.theme-name { flex: 1; color: var(--text-header); }
.ai-layout-preview { background: var(--bg-chat); border: 1px solid var(--bg-deepest); border-radius: var(--radius-lg); padding: 12px; margin: 12px 0; }
.ai-code { background: var(--bg-deepest); border: 1px solid var(--bg-hover); border-radius: var(--radius-lg); padding: 12px; overflow-x: auto; max-height: 300px; font-size: 12px; }

/* ============================================================
   Plugins
   ============================================================ */
.plugin-list { display: flex; flex-direction: column; gap: 4px; margin: 12px 0; }
.plugin-row { display: flex; align-items: center; gap: 12px; padding: 10px 12px; background: var(--bg-deepest); border-radius: var(--radius-lg); }
.plugin-info { flex: 1; display: flex; flex-direction: column; min-width: 0; }
.plugin-info b { color: var(--text-header); }
.plugin-code-view { background: var(--bg-deepest); border: 1px solid var(--bg-hover); border-radius: var(--radius-md); padding: 10px; margin: 0 0 6px; overflow-x: auto; max-height: 240px; font-size: 12px; }
.plugin-add-row { display: flex; gap: 8px; align-items: center; margin-top: 8px; flex-wrap: wrap; }
.plugin-add-row #plugin-name { flex: 1; min-width: 140px; }
.switch { position: relative; display: inline-block; width: 40px; height: 24px; flex: none; }
.switch input { position: absolute; width: 1px; height: 1px; opacity: 0; margin: 0; }
.switch-track { position: absolute; inset: 0; background: #72767d; border-radius: 999px; transition: background-color calc(150ms * var(--anim)) var(--ease); }
.switch-track::before { content: ""; position: absolute; width: 18px; height: 18px; left: 3px; top: 3px; background: #fff; border-radius: 50%; transition: transform calc(150ms * var(--anim)) var(--ease); }
.switch input:checked + .switch-track { background: var(--status-online); }
.switch input:focus-visible + .switch-track { box-shadow: 0 0 0 2px var(--brand); }
.switch input:checked + .switch-track::before { transform: translateX(16px); }

/* ============================================================
   Push notifications
   ============================================================ */
.push-card { background: var(--bg-deepest); border: 1px solid var(--bg-hover); border-radius: var(--radius-xl); padding: 16px; margin: 12px 0; display: flex; flex-direction: column; gap: 12px; }
.push-status { display: flex; align-items: center; gap: 8px; font-weight: 600; color: var(--text-header); }
.push-status-dot { width: 10px; height: 10px; border-radius: 50%; background: var(--text-faint); }
.push-status-dot.on { background: var(--status-online); }
.push-actions { display: flex; gap: 10px; flex-wrap: wrap; }
.push-endpoint { overflow-wrap: anywhere; }

/* ============================================================
   Profile customization controls
   ============================================================ */
/* Clickable avatar/banner previews in the profile editor */
.avatar-pick-row { display: flex; align-items: flex-start; gap: 14px; }
.avatar-pick-actions { display: flex; flex-direction: column; gap: 8px; }

.img-pick { position: relative; display: block; cursor: pointer; overflow: hidden; }
.img-pick::after {
  content: "Edit"; position: absolute; inset: 0; display: grid; place-items: center;
  background: #000000a0; color: #fff; font-size: 13px; font-weight: 600;
  opacity: 0; border-radius: inherit;
  transition: opacity calc(120ms * var(--anim)) var(--ease);
}
.img-pick:hover::after, .img-pick:focus-visible::after { opacity: 1; }
.img-pick:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.img-pick-avatar { width: 96px; height: 96px; border-radius: 50%; flex: none; }

/* Shared "Edit Image" crop modal (avatar + banner pickers) */
.img-modal { width: min(100%, 560px); }
.img-head { padding-bottom: 12px; }
.img-editor { display: flex; flex-direction: column; gap: 14px; }
.img-stage {
  position: relative; overflow: hidden; background: #1a1b1e; border-radius: var(--radius-md);
  touch-action: none; cursor: grab; user-select: none; -webkit-user-select: none;
}
.img-stage:active { cursor: grabbing; }
.img-stage:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.img-stage-avatar { width: 100%; max-width: 340px; aspect-ratio: 1 / 1; margin: 0 auto; }
.img-stage-banner { width: 100%; aspect-ratio: 16 / 9; }
.img-stage-img { position: absolute; display: block; max-width: none; pointer-events: none; }
.img-shade { position: absolute; pointer-events: none; border: 2px solid #fff; box-shadow: 0 0 0 9999px rgba(0, 0, 0, .6); }
.img-shade-avatar { left: 50%; top: 50%; width: 72%; aspect-ratio: 1 / 1; border-radius: 50%; transform: translate(-50%, -50%); }
.img-shade-banner { left: 50%; top: 50%; width: 92%; aspect-ratio: 3 / 1; border-radius: var(--radius-sm); transform: translate(-50%, -50%); }
.img-zoom-row { display: flex; align-items: center; gap: 12px; color: var(--text-muted); }
.img-zoom-ico { flex: none; }
.img-zoom { flex: 1; min-width: 0; accent-color: var(--brand); }
.img-reset-ico { margin-left: auto; }
.img-hint { margin: 0; color: var(--text-muted); font-size: 12px; text-align: center; }
.img-footer { justify-content: space-between; }
.img-footer-actions { display: flex; align-items: center; gap: 12px; }
.secondary-btn {
  background: var(--bg-input); color: var(--text-normal); font-weight: 600; font-size: 15px;
  border-radius: var(--radius-sm); padding: 10px 18px;
  transition: background-color calc(150ms * var(--anim)) var(--ease);
}
.secondary-btn:hover { background: var(--bg-active); }

.avatar-clip { position: absolute; inset: 0; border-radius: var(--avatar-radius); overflow: hidden; display: block; }
.avatar-clip img { width: 100%; height: 100%; object-fit: cover; border-radius: var(--avatar-radius); }
.grad-row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin: 8px 0; transition: opacity calc(150ms * var(--anim)) var(--ease); }
.grad-row.disabled { opacity: .4; pointer-events: none; }
.profile-card-body .pv-avatar { margin-top: -40px; margin-bottom: 6px; }

/* Styled colour trigger + picker popover (profile accent & gradient stops) */
.color-trigger {
  display: inline-flex; align-items: center; gap: 10px;
  background: var(--bg-deepest); border: 1px solid #00000060; border-radius: var(--radius-lg);
  padding: 6px 10px 6px 6px; color: var(--text-normal); cursor: pointer;
  font: inherit; transition: border-color calc(120ms * var(--anim)) var(--ease), background-color calc(120ms * var(--anim)) var(--ease);
}
.color-trigger:hover { border-color: var(--brand); }
.color-trigger:focus-visible { outline: none; border-color: var(--brand); box-shadow: 0 0 0 1px var(--brand); }
.color-trigger-chip { width: 26px; height: 26px; border-radius: var(--radius-md); flex: none; border: 1px solid #00000080; }
.color-trigger-text { display: flex; flex-direction: column; align-items: flex-start; line-height: 1.15; }
.color-trigger-label { font-size: 11px; color: var(--text-muted); text-transform: uppercase; letter-spacing: .04em; }
.color-trigger-hex { font-size: 13px; font-family: var(--font-mono); }

.colorpick-pop { padding: 10px; }
.colorpick { width: 208px; display: flex; flex-direction: column; gap: 10px; }
.colorpick-area {
  position: relative; height: 120px; border-radius: var(--radius-md); cursor: crosshair;
  touch-action: none; background: #f00;
}
.colorpick-thumb, .colorpick-hue-thumb {
  position: absolute; width: 14px; height: 14px; border-radius: 50%;
  border: 2px solid #fff; box-shadow: 0 0 0 1px #00000080;
  transform: translate(-50%, -50%); pointer-events: none;
}
.colorpick-hue {
  position: relative; height: 12px; border-radius: var(--radius-md); cursor: pointer; touch-action: none;
  background: linear-gradient(to right, #f00, #ff0, #0f0, #0ff, #00f, #f0f, #f00);
}
.colorpick-hue-thumb { top: 50%; }
.colorpick-bottom { display: flex; align-items: center; gap: 8px; }
.colorpick-preview { width: 28px; height: 28px; border-radius: var(--radius-md); flex: none; border: 1px solid #00000080; }
.colorpick-hex {
  flex: 1; min-width: 0; background: var(--bg-deepest); border: 1px solid #00000080;
  border-radius: var(--radius-md); color: var(--text-normal); font: inherit; font-size: 13px;
  padding: 6px 8px; text-transform: uppercase;
}
.colorpick-hex:focus { outline: none; border-color: var(--brand); }

/* ============================================================
   Mobile
   ============================================================ */
.mobile-only { display: none; }
body.mobile .mobile-only { display: inline-flex; }
#mobile-nav-btn, #mobile-members-btn {
  position: fixed; top: calc(8px + env(safe-area-inset-top)); z-index: 60;
  width: 44px; height: 44px; border-radius: 50%; background: var(--bg-floating); color: var(--text-header);
  align-items: center; justify-content: center; box-shadow: var(--shadow-elev);
}
#mobile-nav-btn { left: calc(8px + env(safe-area-inset-left)); }
#mobile-members-btn { right: calc(8px + env(safe-area-inset-right)); display: none; }
body.members-compact #mobile-members-btn { display: inline-flex; }
#mobile-scrim { position: fixed; inset: 0; background: rgba(0,0,0,.55); z-index: 30; display: none; }
body.mobile.mobile-scrim-on #mobile-scrim,
body.members-compact.mobile-scrim-on #mobile-scrim { display: block; }
body.mobile .app-body,
body.members-compact .app-body { position: relative; }
body.mobile .channel-header {
  padding-left: 54px; padding-right: 54px;
  /* clear the notch: the header sits at the top, under the status bar */
  padding-top: env(safe-area-inset-top); height: calc(48px + env(safe-area-inset-top));
}
body.members-compact .channel-header {
  padding-right: 54px;
  padding-top: env(safe-area-inset-top); height: calc(48px + env(safe-area-inset-top));
}
body.members-compact .app-shell.mobile-members .member-list {
  display: flex; position: absolute; right: 0; top: 0; height: 100%; z-index: 44;
  padding-top: env(safe-area-inset-top);
  box-shadow: var(--elev-high); background: var(--bg-sidebar);
}
body.mobile .composer-wrap { padding: 0 10px calc(12px + env(safe-area-inset-bottom)); }
body.mobile .rail {
  width: 64px;
  /* top padding clears the floating #mobile-nav-btn, which otherwise covers the
     home/DM button, and the rail is raised above the (closed) drawer so its
     server icons stay tappable — the drawer's off-screen box overlaps the rail.
     The inset keeps the first icon clear of the floating button on notched
     devices, where that button is pushed down by env(safe-area-inset-top). */
  padding: calc(56px + env(safe-area-inset-top)) 6px 12px;
  position: relative;
  z-index: 45;
}
body.mobile .sidebar { width: min(80vw, 300px); }
body.mobile .msg-row { padding-left: 10px; }
body.mobile .modal:not(.qs-modal):not(.confirm-modal) { width: 100% !important; max-width: 100%; }
body.mobile .settings { flex-direction: column; }
body.mobile .settings-nav { width: 100%; flex-direction: row; overflow-x: auto; padding: 8px; gap: 4px; }
body.mobile .settings-nav-item { white-space: nowrap; }
body.mobile .settings-nav-section, body.mobile .settings-nav-sep { display: none; }
body.mobile .settings-content { padding: 12px; }
body.mobile .profile-editor { grid-template-columns: 1fr; }
body.mobile .app-shell.nav-open .sidebar { display: flex; }

@media (max-width: 700px) {
  .rail-btn { width: 48px; height: 48px; }
  .roles-layout { grid-template-columns: 1fr; }
  /* fixed-width floating UI would overflow a phone viewport */
  .picker-popover, .search-panel, .pins-wrap, .inbox-wrap, .threads-wrap, .inbox-pop-wrap {
    width: min(100%, calc(100vw - 16px));
    max-width: calc(100vw - 16px);
    min-width: 0;
  }
  .shortcut-sheet { min-width: 0; width: min(100%, calc(100vw - 24px)); }
  /* friends tabs must scroll rather than wrap/clip next to the nav button */
  .friends-tabs { flex: 1; min-width: 0; overflow-x: auto; scrollbar-width: none; }
  .friends-tab { white-space: nowrap; flex: none; }
  /* give the media viewer the full phone width instead of Discord-desktop insets */
  .mv-stage { padding: 48px 8px; }
  .mv-media, video.mv-media {
    max-width: calc(100vw - 16px);
    max-height: calc(100vh - 96px);
    max-height: calc(100dvh - 96px);
  }
}

/* Coarse pointers need larger hit targets than the WCAG 24px minimum. */
@media (pointer: coarse) {
  .ctx-item, .menu-item { min-height: 40px; }
  .channel-item { height: 42px; }
  .side-section .icon-btn, .channel-settings, .category-add { width: 32px; height: 32px; }
}

/* Touch devices have no :hover/:focus-within for a finger, so controls that
   are only revealed on hover become invisible and untappable. Show them. */
@media (hover: none) {
  .friend-row .friend-actions,
  .dm-close,
  .channel-settings,
  .category-add,
  .pin-unpin { opacity: 1; }
  /* .msg-hover-actions is opacity:0 + pointer-events:none until hover/focus,
     which never fires on touch — reveal it so reply/react/edit/delete work. */
  .msg-row .msg-hover-actions { opacity: 1; pointer-events: auto; }
  /* hover-only chrome that is otherwise unreachable with a finger */
  .code-copy,
  .msg-video-expand,
  .gifpicker-name { opacity: 1; }
  /* reserve room for the always-visible action bar once per group, not on every
     row (per-row margins broke the tight spacing between consecutive messages) */
  .msg-group { padding-top: 16px; }
  .msg-group:first-of-type { padding-top: 20px; }
}

/* ============================================================
   Polish
   ============================================================ */
.account-banner.has-image { background-size: cover; background-position: center; }
.pcard-banner.has-image { background-size: cover; background-position: center; }

/* Visually hidden but announced by screen readers (live-region message feed). */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

/* Markdown dynamic timestamps (<t:unix>) render as a muted chip. */
.md-timestamp { background: var(--bg-deepest); border-radius: var(--radius-sm); padding: 1px 4px; font-size: .85em; }

/* Edit failures are errors, not the normal muted hint. */
.edit-error { color: #f23f43; }
.edit-error .link-btn { color: #f23f43; text-decoration: underline; }

/* Profile display name that inserts an @mention on click. */
.clickable-mention { cursor: pointer; }
.clickable-mention:hover { text-decoration: underline; }

/* ============================================================
   Themable effects
   Driven by the AI theme generator's motion/effect tokens. With the default
   values (--glass: 0px, --glass-alpha: 100%, --accent-gradient: none) every
   rule below resolves to the original opaque, flat surfaces.
   ============================================================ */
/* Frosted floating panels. */
.autocomplete, .popover, .tooltip, .quick-switcher, .toast, .slash-pop {
  background: color-mix(in srgb, var(--bg-floating) var(--glass-alpha), transparent);
  -webkit-backdrop-filter: blur(var(--glass));
  backdrop-filter: blur(var(--glass));
}
.modal {
  background: color-mix(in srgb, var(--bg-chat) var(--glass-alpha), transparent);
  -webkit-backdrop-filter: blur(var(--glass));
  backdrop-filter: blur(var(--glass));
}
.profile-card {
  background: color-mix(in srgb, var(--bg-deepest) var(--glass-alpha), transparent);
  -webkit-backdrop-filter: blur(var(--glass));
  backdrop-filter: blur(var(--glass));
}

/* Accent gradients layered over brand-coloured surfaces. */
.rail-btn.home-btn.active, .rail-btn.server-btn.active, .ai-user { background-image: var(--accent-gradient); }

/* ============================================================
   Theme assets & layout (advanced theming)
   Defaults (--bg-image: none, --bg-*-image: none, --theme-cursor: auto,
   --theme-logo: none) reproduce the plain design exactly.
   ============================================================ */
::selection { background: var(--selection-bg); }

/* Whole-app backdrop image, painted behind the main surfaces. */
body::before {
  content: ""; position: fixed; inset: 0; z-index: -1; pointer-events: none;
  background-image: var(--bg-image);
  background-size: var(--bg-image-size);
  background-position: var(--bg-image-position);
  background-repeat: var(--bg-image-repeat);
  background-attachment: var(--bg-image-attachment);
  background-blend-mode: var(--bg-image-blend);
  opacity: var(--bg-image-opacity);
}
/* Let the backdrop show through the main surfaces when one is set. */
html[data-theme-bg] .rail,
html[data-theme-bg] .sidebar,
html[data-theme-bg] .member-list,
html[data-theme-bg] .content { background-color: transparent; }

/* Per-region images layered over the opaque surface colour. */
.sidebar, .member-list {
  background-image: var(--bg-sidebar-image); background-size: cover;
  background-position: center; background-repeat: no-repeat;
}
.content {
  background-image: var(--bg-chat-image); background-size: cover;
  background-position: center; background-repeat: no-repeat;
}

/* Custom cursor (falls back to auto when no asset is set). */
html { cursor: var(--theme-cursor); }

/* Custom home logo overlays the default glyph. */
.rail-btn.home-btn { position: relative; }
.rail-btn.home-btn::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  background-image: var(--theme-logo); background-size: cover; background-position: center;
}
html[data-theme-logo] .rail-btn.home-btn svg,
html[data-theme-logo] .rail-btn.home-btn i { display: none; }

/* ============================================================
   Theme Studio editor
   ============================================================ */
.theme-editor { border: 1px solid var(--bg-deep); border-radius: var(--radius-lg); padding: 14px; margin: 14px 0; }
.theme-editor-head { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-bottom: 14px; }
.theme-editor-head .field-input { flex: 1; min-width: 180px; }
.theme-editor-section { border-top: 1px solid var(--bg-deep); padding-top: 12px; margin-top: 12px; }
.theme-editor-title { color: var(--text-muted); font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .4px; margin-bottom: 10px; }
.theme-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); gap: 8px; }
.theme-grid-wide { grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); }
.theme-color { display: flex; flex-direction: column; gap: 4px; }
.theme-color input[type="color"] { width: 100%; height: 30px; border: 1px solid var(--bg-deep); border-radius: var(--radius-sm); background: var(--bg-deepest); cursor: pointer; padding: 0; }
.theme-color-name { color: var(--text-muted); font-size: 11px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.theme-slider { display: flex; flex-direction: column; gap: 4px; }
.theme-slider-label { color: var(--text-normal); font-size: 12.5px; }
.theme-slider input[type="range"] { width: 100%; accent-color: var(--brand); }
.theme-slider-value { color: var(--text-muted); font-size: 11.5px; font-variant-numeric: tabular-nums; }
.theme-field { display: flex; flex-direction: column; gap: 4px; }
.theme-field-label { color: var(--text-normal); font-size: 12.5px; }
.theme-asset-list { display: flex; flex-direction: column; gap: 8px; }
.theme-asset { display: flex; align-items: center; gap: 10px; }
.theme-asset-preview { width: 42px; height: 30px; flex: none; border-radius: var(--radius-sm); background: var(--bg-deepest); border: 1px solid var(--bg-deep); background-size: cover; background-position: center; }
.theme-asset-preview.has-image { border-color: var(--brand); }
.theme-asset-info { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.theme-asset-info b { color: var(--text-normal); font-size: 13px; font-weight: 600; }
.theme-font-row { display: flex; gap: 8px; align-items: center; margin-top: 10px; }
.theme-font-row .field-input { flex: 1; min-width: 140px; }
.theme-check { display: inline-flex; align-items: center; gap: 6px; color: var(--text-normal); font-size: 13px; white-space: nowrap; }
.theme-check input { accent-color: var(--brand); }
.theme-textarea { margin-top: 10px; font-family: var(--font-mono); font-size: 12.5px; }
.theme-textarea:disabled { opacity: .5; }

/* ============================================================
   Charts 2.0 (ECharts canvas + a11y table), rich embeds,
   markdown alerts, and bot streaming skeletons
   ============================================================ */
.md-chart-canvas { width: 100%; height: 210px; }
.md-chart-canvas svg { width: 100%; height: 100%; }
.md-chart-title { text-transform: none; letter-spacing: 0; }
.md-chart-a11y {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.md-alert {
  border-left: 4px solid var(--brand); background: rgba(88,101,242,.10);
  border-radius: var(--radius-md); padding: 8px 12px; margin: 6px 0; font-size: 14px;
}
.md-alert-title { font-weight: 700; color: var(--text-header); margin-bottom: 2px; }
.md-alert-body { color: var(--text-normal); }
.md-alert-info { border-left-color: #3b82f6; background: rgba(59,130,246,.10); }
.md-alert-success { border-left-color: #57f287; background: rgba(87,242,135,.10); }
.md-alert-brand { border-left-color: var(--brand); background: rgba(88,101,242,.12); }
.md-alert-warning { border-left-color: #fee75c; background: rgba(254,231,92,.10); }
.md-alert-danger { border-left-color: #ed4245; background: rgba(237,66,69,.10); }

/* rich bot embeds */
.msg-embed-rich { display: flex; gap: 10px; background: var(--bg-deep); border-radius: var(--radius-md); padding: 10px 12px; max-width: 520px; position: relative; }
.embed-rich-bar { position: absolute; left: 0; top: 0; bottom: 0; width: 4px; border-radius: var(--radius-md) 0 0 var(--radius-md); background: var(--embed-color, var(--brand)); }
.embed-rich-body { display: flex; flex-direction: column; gap: 6px; min-width: 0; flex: 1; }
.embed-author { display: flex; align-items: center; gap: 8px; }
.embed-author-icon { width: 24px; height: 24px; border-radius: 50%; object-fit: cover; }
.embed-author-name { font-size: 13px; font-weight: 700; color: var(--text-header); text-decoration: none; }
.embed-fields { display: flex; flex-wrap: wrap; gap: 8px 18px; }
.embed-field { min-width: 0; flex: 1 1 100%; }
.embed-field.inline { flex: 1 1 30%; }
.embed-field-name { font-size: 12px; font-weight: 700; color: var(--text-header); }
.embed-field-value { font-size: 13.5px; color: var(--text-normal); white-space: pre-wrap; }
.embed-footer { display: flex; align-items: center; gap: 8px; font-size: 12px; color: var(--text-muted); margin-top: 2px; }
.embed-footer-icon { width: 18px; height: 18px; border-radius: 50%; object-fit: cover; }
.embed-footer-time { margin-left: auto; }
.embed-thumb { width: 72px; height: 72px; flex: none; border-radius: var(--radius-sm); object-fit: cover; background: var(--bg-deepest); }

/* bot streaming skeletons */
.cmp-skeleton { display: flex; flex-direction: column; gap: 7px; padding: 2px 0; min-width: min(220px, 100%); max-width: min(460px, 100%); }
.cmp-skeleton-title { font-size: 12px; color: var(--text-muted); }
.cmp-skeleton-block, .cmp-skeleton-line {
  display: block; height: 12px; border-radius: var(--radius-sm);
  background: linear-gradient(90deg, var(--bg-deep) 25%, var(--bg-deepest) 37%, var(--bg-deep) 63%);
  background-size: 400% 100%; animation: skeleton-sweep calc(1400ms * var(--anim)) var(--ease-in-out) infinite;
}
/* Sweep the gradient (background-position) rather than translating the bar
   itself: the shared `shimmer` keyframes translate by 100% and are meant for
   the ::after overlay, so reusing them here slid the whole block out of the
   message column and clipped it. */
@keyframes skeleton-sweep { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }
@media (prefers-reduced-motion: reduce) {
  .cmp-skeleton-block, .cmp-skeleton-line { animation: none; }
}
.cmp-skeleton-track { height: 8px; border-radius: 4px; background: var(--bg-deepest); overflow: hidden; }
.cmp-skeleton-bar { height: 100%; background: var(--brand); border-radius: 4px; transition: width .3s var(--ease-out); }
.cmp-skeleton-pct { font-size: 11px; color: var(--text-muted); align-self: flex-end; margin-top: -4px; }
.cmp-skeleton-spinner { flex-direction: row; align-items: center; }
.cmp-spinner {
  width: 16px; height: 16px; border-radius: 50%; flex: none;
  border: 2px solid var(--bg-deepest); border-top-color: var(--brand);
  animation: cmp-spin calc(900ms * var(--anim)) linear infinite;
}
@keyframes cmp-spin { to { transform: rotate(360deg); } }

/* ============================================================
   Economy 2.0 UI: jobs, casino, bank, orders, book
   ============================================================ */
.eco-stat-row { display: flex; flex-wrap: wrap; gap: 10px; margin: 10px 0; }
.eco-stat { display: flex; flex-direction: column; gap: 2px; background: var(--bg-deep); border: 1px solid var(--bg-deepest); border-radius: var(--radius-md); padding: 8px 14px; min-width: 96px; }
.eco-stat b { font-size: 18px; color: var(--text-header); }
.eco-job-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 10px; margin-top: 8px; }
.eco-job-card { background: var(--bg-deep); border: 1px solid var(--bg-deepest); border-radius: var(--radius-md); padding: 12px; display: flex; flex-direction: column; gap: 8px; }
.eco-job-card h3 { font-size: 15px; color: var(--text-header); }
.eco-job-card .primary-btn { align-self: flex-start; }
.eco-bet-row { display: flex; flex-wrap: wrap; gap: 12px; align-items: flex-end; margin: 10px 0; }
.eco-bet-row .field { flex: 1 1 160px; }
.eco-casino-row { display: flex; flex-wrap: wrap; gap: 8px; margin: 10px 0; }
.eco-result { display: block; padding: 10px; background: var(--bg-deep); border-radius: var(--radius-md); min-height: 20px; }
.eco-order-form { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin: 10px 0; }
.eco-order-form .field-input { flex: 1 1 110px; min-width: 90px; }
.eco-order-list { display: flex; flex-direction: column; gap: 6px; }
.eco-order-row { display: flex; align-items: center; gap: 8px; background: var(--bg-deep); border: 1px solid var(--bg-deepest); border-radius: var(--radius-sm); padding: 6px 10px; font-size: 13px; }
.eco-order-row .link-btn { margin-left: auto; }
.eco-book { background: var(--bg-deep); border: 1px solid var(--bg-deepest); border-radius: var(--radius-md); padding: 10px; margin: 8px 0; }
.eco-book-cols { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.eco-book-side { display: flex; flex-direction: column; gap: 3px; }
.eco-book-side.asks { text-align: right; }
.eco-book-level { display: flex; justify-content: space-between; gap: 10px; font-size: 12.5px; font-variant-numeric: tabular-nums; }
.eco-book-side.bids .eco-book-level { color: #57f287; }
.eco-book-side.asks .eco-book-level { color: #ed4245; }
.eco-chart-wrap { margin: 10px 0; }

/* ============================================================
   Attachment image editor (imageeditor.js)
   ============================================================ */
.imged {
  position: fixed; inset: 0; z-index: 120;
  display: flex; flex-direction: column;
  background: var(--bg-deepest); color: var(--text-normal);
  animation: imged-in calc(140ms * var(--anim)) var(--ease);
}
.imged.closing { opacity: 0; transition: opacity calc(120ms * var(--anim)) var(--ease); }
@keyframes imged-in { from { opacity: 0; } to { opacity: 1; } }

.imged-top {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 14px; background: var(--bg-sidebar);
  border-bottom: 1px solid var(--bg-deepest); flex: none;
}
.imged-icon { color: var(--text-muted); display: flex; }
.imged-title {
  flex: 1; min-width: 0; font-weight: 600; color: var(--text-header);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.imged-actions { display: flex; align-items: center; gap: 8px; }

.imged-body { display: flex; flex: 1; min-height: 0; }

.imged-tools {
  display: flex; flex-direction: column; gap: 4px; padding: 8px;
  width: 92px; flex: none; overflow-y: auto;
  background: var(--bg-sidebar); border-right: 1px solid var(--bg-deepest);
}
.imged-tool {
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  padding: 8px 4px; border: 0; border-radius: var(--radius-md);
  background: transparent; color: var(--text-muted);
  font: inherit; font-size: 11px; line-height: 1; cursor: pointer;
}
.imged-tool:hover { background: var(--bg-hover); color: var(--text-normal); }
.imged-tool.active { background: var(--brand); color: #fff; }
.imged-tool-label { font-size: 10.5px; font-weight: 600; }

.imged-stage {
  position: relative; flex: 1; min-width: 0; overflow: hidden;
  display: grid; place-items: center; touch-action: none;
  background-color: var(--bg-deepest);
  background-image:
    linear-gradient(45deg, var(--bg-deep) 25%, transparent 25%, transparent 75%, var(--bg-deep) 75%),
    linear-gradient(45deg, var(--bg-deep) 25%, transparent 25%, transparent 75%, var(--bg-deep) 75%);
  background-size: 24px 24px;
  background-position: 0 0, 12px 12px;
}
.imged-wrap { position: relative; transform-origin: center center; }
.imged-canvas { display: block; background: #fff; box-shadow: var(--shadow-elev); }
.imged-overlay { position: absolute; left: 0; top: 0; pointer-events: none; }

.imged-handle {
  position: absolute; width: 12px; height: 12px; border-radius: 2px;
  background: #fff; border: 1.5px solid var(--brand); pointer-events: auto; cursor: pointer;
}
.imged-handle-rotate { border-radius: 50%; cursor: grab; }
.imged-selectbox { position: absolute; border: 1.5px dashed rgba(255,255,255,.85); pointer-events: none; }
.imged-crop-shade { position: absolute; box-shadow: 0 0 0 9999px rgba(0,0,0,.55); pointer-events: none; }
.imged-crop-box { position: absolute; border: 1.5px solid #fff; pointer-events: auto; cursor: move; }
.imged-gridline { position: absolute; background: rgba(255,255,255,.35); pointer-events: none; }

.imged-inspector {
  width: 296px; flex: none; padding: 12px; overflow-y: auto;
  display: flex; flex-direction: column; gap: 10px;
  background: var(--bg-sidebar); border-left: 1px solid var(--bg-deepest);
}
.imged-section { display: flex; flex-direction: column; gap: 8px; }
.imged-section-title {
  font-size: 11px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .04em; color: var(--text-muted);
}
.imged-row { display: flex; gap: 6px; flex-wrap: wrap; }
.imged-field { display: flex; flex-direction: column; gap: 4px; font-size: 12.5px; }
.imged-field-inline { flex-direction: row; align-items: center; justify-content: space-between; }
.imged-field-label { color: var(--text-muted); font-weight: 600; }
.imged-muted { color: var(--text-faint); font-weight: 400; }
.imged-range { width: 100%; accent-color: var(--brand); }
.imged-field-inline .imged-range { width: 130px; }
.imged-color {
  width: 40px; height: 26px; padding: 0; cursor: pointer;
  border: 1px solid var(--bg-deepest); border-radius: var(--radius-sm); background: var(--bg-input);
}
.imged-select {
  padding: 6px 8px; font: inherit; color: var(--text-normal);
  border: 1px solid var(--bg-deepest); border-radius: var(--radius-sm); background: var(--bg-input);
}
.imged-check { width: 16px; height: 16px; accent-color: var(--brand); }
.imged-text {
  width: 100%; resize: vertical; padding: 8px; font: inherit;
  color: var(--text-normal); border: 1px solid var(--bg-deepest);
  border-radius: var(--radius-sm); background: var(--bg-input);
}
.imged-btn {
  display: inline-flex; align-items: center; gap: 6px; padding: 6px 10px;
  font: inherit; font-size: 13px; cursor: pointer; color: var(--text-normal);
  border: 1px solid var(--bg-deepest); border-radius: var(--radius-sm); background: var(--bg-input);
}
.imged-btn:hover { background: var(--bg-hover); }
.imged-presets { display: flex; gap: 6px; flex-wrap: wrap; }
.imged-empty { margin: 0; font-size: 12.5px; color: var(--text-muted); }

.imged-layers { display: flex; flex-direction: column; gap: 4px; }
.imged-layer { display: flex; align-items: center; gap: 4px; padding: 4px 6px; border-radius: var(--radius-sm); background: var(--bg-deep); }
.imged-layer.active { outline: 1.5px solid var(--brand); }
.imged-layer-name {
  flex: 1; min-width: 0; font-size: 12.5px; color: var(--text-normal);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.imged-layer-eye, .imged-layer-btn {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 22px; height: 22px; border: 0; border-radius: var(--radius-xs);
  background: transparent; color: var(--text-muted); cursor: pointer;
}
.imged-layer-eye:hover, .imged-layer-btn:hover { background: var(--bg-hover); color: var(--text-header); }

.imged-foot {
  display: flex; align-items: center; gap: 14px; flex: none;
  padding: 8px 14px; font-size: 12.5px;
  background: var(--bg-sidebar); border-top: 1px solid var(--bg-deepest);
}
.imged-zoom { display: flex; align-items: center; gap: 6px; }
.imged-zoom .imged-range { width: 120px; }
.imged-dims { color: var(--text-muted); font-variant-numeric: tabular-nums; }
.imged-export { display: flex; align-items: center; gap: 10px; margin-left: auto; }
.imged-export .imged-range { width: 100px; }

@media (max-width: 860px) {
  .imged-body { flex-direction: column; }
  .imged-tools {
    flex-direction: row; width: auto; overflow-x: auto;
    border-right: 0; border-bottom: 1px solid var(--bg-deepest);
  }
  .imged-tool { flex: none; }
  .imged-tool-label { display: none; }
  .imged-inspector { width: auto; max-height: 42%; border-left: 0; border-top: 1px solid var(--bg-deepest); }
}
@media (max-width: 700px) {
  /* the zoom cluster + export controls must be able to wrap rather than push
     the format select past the viewport at phone widths */
  .imged-foot { flex-wrap: wrap; gap: 8px 12px; }
  .imged-zoom .imged-range { width: 90px; }
  .imged-export { margin-left: 0; }
}
@media (max-width: 560px) {
  .imged-title { display: none; }
  .imged-export .imged-field-label { display: none; }
}
