:root {
  --font-family: 'Poppins', sans-serif;
  --bg-color: #101214;
  --surface-color: #191c20;
  --primary-text: #f4f6f8;
  --secondary-text: #a7b0bb;
  --accent-color: #4f8cff;
  --link-color: #9cc3ff;
  --agent-bubble: #242932;
  --user-bubble-start: #2f6fed;
  --user-bubble-end: #2557c7;
  --error-color: #CF6679;
  --error-bg-color: rgba(207,102,121,0.2);
  --border-color: #333;
  --input-bg-color: #404040;
  --input-border-color: #555;
  --scrollbar-thumb-color: #555;
  --modal-overlay-bg: rgba(0,0,0,0.7);
  --modal-button-secondary-bg: #555;
  --modal-button-secondary-text: var(--primary-text);
  --text-primary: var(--primary-text);
  --text-secondary: var(--secondary-text);
  --button-bg: rgba(255,255,255,0.05);
  --button-bg-hover: rgba(255,255,255,0.08);
  --icon-color: var(--secondary-text);
  --accent-color-hover: color-mix(in srgb, var(--accent-color) 85%, #000 15%);
  --header-height: auto;
  --bubble-radius: 16px;
}


body[data-theme="light"] {
  --bg-color: #F5F5F5;
  --surface-color: #FFFFFF;
  --primary-text: #212121;
  --secondary-text: #757575;
  --accent-color: #6200EE;
  --link-color: #4a1fd1;
  --agent-bubble: #F0F0F0;
  --user-bubble-start: #3F51B5;
  --user-bubble-end: #303F9F;
  --error-color: #B00020;
  --error-bg-color: rgba(176,0,32,0.1);
  --border-color: #E0E0E0;
  --input-bg-color: #E0E0E0;
  --input-border-color: #BDBDBD;
  --scrollbar-thumb-color: #BDBDBD;
  --modal-overlay-bg: rgba(0,0,0,0.5);
  --modal-button-secondary-bg: #E0E0E0;
  --modal-button-secondary-text: var(--primary-text);
}

body[data-theme="midnight"] {
  --bg-color: #0d1117;
  --surface-color: #161b22;
  --primary-text: #c9d1d9;
  --secondary-text: #8b949e;
  --accent-color: #58a6ff;
  --link-color: #79c0ff;
  --agent-bubble: #21262d;
  --user-bubble-start: #304a69;
  --user-bubble-end: #233e60;
  --error-color: #f85149;
  --error-bg-color: rgba(248,81,73,0.15);
  --border-color: #30363d;
  --input-bg-color: #0d1117;
  --input-border-color: #30363d;
  --scrollbar-thumb-color: #30363d;
  --modal-overlay-bg: rgba(0,0,0,0.7);
  --modal-button-secondary-bg: #21262d;
  --modal-button-secondary-text: var(--primary-text);
}

*, *::before, *::after { box-sizing: border-box; }
html, body { height: 100%; margin: 0; max-width: 100%; overflow-x: hidden; touch-action: pan-x pan-y; }
/* Paint the root/canvas itself dark. During a webview fullscreen/resize
   transition (and behind body's safe-area padding gutter), the browser shows
   the canvas color before body's gradient repaints -- with no html background
   that canvas defaults to white, which flashed for a couple seconds when
   entering fullscreen. A solid dark here keeps that area theme-colored. */
html { background-color: #081a33; }
/* The hidden attribute must always hide, even on elements whose class sets
   display (.icon-button, .nav-menu-item, .modal-button ...). Without this,
   an author display rule beats the UA [hidden] default, so hidden is
   silently ignored -- which left routes-btn (and its owner-only gating)
   permanently visible and pushed the logout icon into the flexible column
   as a full-width bar. */
[hidden] { display: none !important; }
html { -webkit-text-size-adjust: 100%; }
body {
  font-family: var(--font-family);
  background: linear-gradient(180deg, #061326 0%, #081a33 42%, #0b1021 100%);
  color: var(--primary-text);
  display: block;
  padding: 3px;
  transition: background-color .3s ease, color .3s ease;
}
.right-align { margin-left: auto; margin-right: 0; }

body::before {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(135deg, rgba(59,130,246,.08), transparent 30%, rgba(99,102,241,.07));
  z-index: -1;
}

.app-shell {
  width: 100%;
  max-width: 100%;
  overflow-x: hidden;
  height: calc(100vh - 6px);
  height: calc(100dvh - 6px);
  min-height: 560px;
  margin: 0 auto;
  display: flex;
  gap: 14px;
}

#history-sidebar {
  width: clamp(210px, 20vw, 248px);
  min-width: 210px;
  background: var(--surface-color);
  border: 1px solid var(--border-color);
  border-radius: 10px;
  box-shadow: 0 16px 44px rgba(0,0,0,.22);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.history-header {
  padding: .75rem .9rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  border-bottom: 1px solid var(--border-color);
}

.history-header h2 {
  margin: 0;
  font-size: .95rem;
  font-weight: 600;
  color: var(--primary-text);
}

.history-header-actions {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
}

#history-close-btn {
  display: none;
}

#chat-history-list {
  padding: .55rem;
  display: flex;
  flex-direction: column;
  gap: .45rem;
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
}

#chat-history-list::-webkit-scrollbar { width: 6px; }
#chat-history-list::-webkit-scrollbar-thumb {
  background: var(--scrollbar-thumb-color);
  border-radius: 3px;
}

.history-empty {
  color: var(--secondary-text);
  font-size: .82rem;
  padding: .75rem;
}

.history-item-row {
  width: 100%;
  position: relative;
}

.history-item {
  width: 100%;
  text-align: left;
  background: var(--input-bg-color);
  border: 1px solid var(--border-color);
  border-radius: 10px;
  padding: .65rem 4.35rem .65rem .7rem;
  color: var(--primary-text);
  cursor: pointer;
  transition: border-color .2s ease, transform .2s ease;
}

.history-item:hover {
  border-color: var(--accent-color);
  transform: translateY(-1px);
}

.history-item.active {
  border-color: var(--accent-color);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent-color) 20%, transparent);
}

.history-item-title {
  font-size: .86rem;
  font-weight: 600;
  margin-bottom: 3px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.history-item-agent,
.history-item-time {
  font-size: .74rem;
  color: var(--secondary-text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.history-copy-btn,
.history-delete-btn {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 28px;
  min-width: 28px;
  height: 28px;
  border: 1px solid var(--border-color);
  border-radius: 8px;
  background: color-mix(in srgb, var(--input-bg-color) 88%, transparent);
  color: var(--secondary-text);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: border-color .2s ease, color .2s ease, background .2s ease;
}

.history-copy-btn {
  right: 38px;
}

.history-delete-btn {
  right: 6px;
}

.history-copy-btn svg,
.history-delete-btn svg {
  width: 16px;
  height: 16px;
}

.history-copy-btn:hover {
  border-color: var(--accent-color);
  color: var(--primary-text);
  background: color-mix(in srgb, var(--accent-color) 12%, var(--input-bg-color));
}

.history-delete-btn:hover {
  border-color: var(--error-color);
  color: #fff;
  background: color-mix(in srgb, var(--error-color) 88%, #000 12%);
}

.history-more-btn {
  width: 100%;
  border: 1px solid var(--border-color);
  border-radius: 10px;
  background: transparent !important;
  color: var(--secondary-text);
  cursor: pointer;
  padding: .6rem .75rem;
  font-size: .82rem;
  font-weight: 600;
  transition: border-color .2s ease, color .2s ease, background .2s ease;
}

.history-more-btn:hover:not(:disabled) {
  border-color: var(--accent-color);
  color: var(--primary-text);
  background: color-mix(in srgb, var(--accent-color) 10%, transparent);
}

.history-more-btn:disabled {
  cursor: default;
  opacity: .65;
}

.chat-main {
  flex: 1;
  min-width: 0;
  display: flex;
}

.chat-container {
  width: 100%; max-width: 100%; min-width: 0; height: 100%;
  background: var(--surface-color);
  border-radius: 10px;
  border: 1px solid var(--border-color);
  box-shadow: 0 16px 44px rgba(0,0,0,.22);
  display: flex; flex-direction: column; overflow: hidden;
  position: relative;
  transition: background-color .2s ease;
}


.mobile-agent-mark {
  display: none;
}

.chat-header {
  padding: .75rem 1rem;
  background: color-mix(in srgb, var(--surface-color) 94%, var(--bg-color));
  display: grid;
  grid-template-columns: 1fr;
  gap: .6rem;
  flex-shrink: 0; border-bottom: 1px solid var(--border-color);
}
.chat-header h1 {
  display: none;
  font-size: 1.05rem; margin: 0; font-weight: 600;
  color: var(--primary-text);
  min-width: 0;
  letter-spacing: 0;
}

.chat-header .mobile-title { display: none; }
.controls-wrapper {
  display: grid;
  grid-template-columns: repeat(6, 42px) minmax(0, 1fr) minmax(0, 150px);
  align-items: center;
  gap: .45rem;
  min-width: 0;
  width: 100%;
}

.nav-menu {
  display: none;
  position: relative;
  grid-column: 2;
  justify-self: end;
  z-index: 20;
}

.nav-menu-button {
  background: rgba(15,23,42,.72);
  border-color: rgba(125,211,252,.28);
  color: color-mix(in srgb, var(--secondary-text) 62%, #bae6fd 38%);
}

.nav-menu-panel {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  min-width: 168px;
  padding: 6px;
  border-radius: 12px;
  border: 1px solid rgba(125,211,252,.22);
  background: rgba(15,23,42,.94);
  box-shadow: 0 16px 34px rgba(2,8,23,.42), inset 0 1px 0 rgba(255,255,255,.06);
  backdrop-filter: blur(12px);
}

.nav-menu-item {
  display: flex;
  width: 100%;
  align-items: center;
  min-height: 38px;
  padding: 9px 11px;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--primary-text);
  font: inherit;
  font-size: .86rem;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
}

.nav-menu-item:hover {
  background: rgba(56,189,248,.12);
}

.agent-url-group {
  display: grid;
  grid-template-columns: 96px minmax(0, 1fr);
  align-items: center;
  gap: .5rem;
  min-width: 0;
}
.agent-url-group label {
  font-size: .8rem; color: var(--secondary-text); font-weight: 500;
  white-space: nowrap;
}

.theme-selector-group { display: none !important; }
.theme-selector-group {
  display: flex;
  align-items: center;
  grid-column: 6;
  min-width: 0;
}
.theme-selector-group label { display: none; }
#theme-selector,
#agent-gateway-select,
#agent-url-input,
#agent-route-select,
#gateway-manual-input {
  background: var(--input-bg-color);
  border: 1px solid var(--border-color);
  color: var(--primary-text);
  font-family: var(--font-family); font-size: .8rem;
  padding: 6px 10px; border-radius: 8px;
}

/* Agent picker: sits inline in the Agent URL row (dropdown + URL + search),
   shown only when the selected gateway publishes agents. */
#agent-route-select {
  min-width: 0;
  box-sizing: border-box;
  cursor: pointer;
}
#agent-route-select:focus { outline: none; border-color: var(--accent-color); }
#agent-route-select option { background: var(--surface-color); color: var(--primary-text); }

#theme-selector,
#agent-gateway-select {
  cursor: pointer;
}
#theme-selector {
  width: 100%;
  min-width: 0;
}
#theme-selector:focus { outline: none; border-color: var(--accent-color); }
#theme-selector option { background: var(--surface-color); color: var(--primary-text); }

/* Custom dropdown that replaces the native <select> popup. The Z-UP app's
   embedded Qt WebEngine webview crashes on macOS when a native <select> opens
   its Cocoa popup menu (native HIToolbox/AppKit path), so script.js hides the
   real <select> (.csel-native) and renders this in-page instead. */
.csel-native { display: none !important; }
.csel { position: relative; display: inline-flex; box-sizing: border-box; }
.csel[hidden] { display: none !important; }
.csel-trigger {
  display: flex; align-items: center; gap: .4rem;
  width: 100%; min-width: 0; box-sizing: border-box;
  background: var(--input-bg-color);
  border: 1px solid var(--border-color);
  color: var(--primary-text);
  font-family: var(--font-family); font-size: .85rem;
  padding: 8px 12px; border-radius: 8px;
  cursor: pointer; text-align: left;
}
/* Agent-URL row: keep the picker and the URL field both at the smaller picker
   size, and equal to each other (equal width comes from flex:1 1 0). */
.agent-url-input-row > .csel .csel-trigger,
.agent-url-input-row > #agent-url-input {
  padding: 6px 10px;
  font-size: .8rem;
}
.csel-trigger:focus { outline: none; border-color: var(--accent-color); }
.csel-trigger[aria-expanded="true"] { border-color: var(--accent-color); }
.csel-label {
  flex: 1 1 auto; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.csel-caret { flex: 0 0 auto; opacity: .7; font-size: .7em; }
.csel-disabled .csel-trigger { cursor: default; opacity: .55; }
.csel-panel {
  position: absolute; top: calc(100% + 4px); left: 0;
  min-width: 100%; max-width: min(92vw, 460px);
  max-height: 260px; overflow-y: auto;
  z-index: 1200;
  background: var(--surface-color);
  border: 1px solid var(--border-color);
  border-radius: 8px;
  box-shadow: 0 10px 30px rgba(0,0,0,.35);
  padding: 4px;
}
.csel-option {
  padding: 7px 10px; border-radius: 6px;
  color: var(--primary-text); font-size: .82rem;
  cursor: pointer; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}
.csel-option:hover { background: color-mix(in srgb, var(--accent-color) 18%, transparent); }
.csel-option[aria-selected="true"] { background: color-mix(in srgb, var(--accent-color) 28%, transparent); }
.csel-option-disabled { opacity: .5; cursor: default; }
.csel-option-disabled:hover { background: transparent; }

/* Occupy the same layout slot the native selects used. */
.agent-url-input-row > .csel { flex: 1 1 0; min-width: 0; }
.gateway-select-row > .csel { min-width: 0; width: 100%; }

#agent-url-input {
  padding: 8px 12px; font-size: .85rem;
  transition: all .2s ease;
  width: 100%;
  min-width: 0;
}
#agent-url-input:focus {
  outline: none; border-color: var(--accent-color);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent-color) 15%, transparent);
}

.gateway-url-group {
  width: 100%;
  max-width: none;
  order: 20;
  grid-column: 1 / -1;
}

.agent-address-group {
  width: 100%;
  max-width: none;
  grid-column: 1 / -1;
}

.agent-url-input-row {
  display: flex;
  align-items: center;
  gap: .4rem;
  min-width: 0;
}
/* The agent dropdown and the URL field share the row's flexible space; the
   registry-search button and the reserved spacer keep their fixed width so the
   row's right edge lines up with the Gateway dropdown's [+][-] buttons. */
.agent-url-input-row > #agent-route-select,
.agent-url-input-row > #agent-url-input {
  flex: 1 1 0;
  min-width: 0;
  width: auto;
}
.agent-url-input-row > #open-registry-btn {
  flex: 0 0 auto;
}

.agent-url-input-row::after {
  content: "";
  flex: 0 0 auto;
  display: block;
  width: 42px;
  height: 1px;
}

.agent-url-group:not(.gateway-url-group) {
  order: 30;
}

.gateway-select-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 42px 42px;
  align-items: center;
  gap: .4rem;
  min-width: 0;
}

#agent-gateway-select {
  padding: 8px 12px;
  font-size: .85rem;
  min-width: 0;
  width: 100%;
}

#agent-gateway-select:focus {
  outline: none;
  border-color: var(--accent-color);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent-color) 15%, transparent);
}

.gateway-add-button,
.gateway-delete-button {
  width: 36px;
  height: 36px;
  flex: 0 0 auto;
}

/* Gateway access-control toggle inside the Relay Routes modal. */
.routes-access-row {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}
.routes-access-state {
  font-weight: 700;
  padding: 2px 10px;
  border-radius: 999px;
  border: 1px solid var(--border-color, #444);
  color: var(--text-secondary-color, #aaa);
}
.routes-access-state.is-restricted {
  color: var(--accent-color, #4c9ffe);
  border-color: var(--accent-color, #4c9ffe);
}

.gateway-delete-button span {
  font-size: 22px;
  font-weight: 700;
  line-height: 1;
}

.gateway-delete-button:hover:not(:disabled) {
  background: var(--error-bg-color);
  border-color: var(--error-color);
  color: var(--error-color);
}

.gateway-delete-button:disabled {
  opacity: .45;
  cursor: not-allowed;
}

.gateway-manual-row {
  display: flex;
  align-items: center;
  gap: .4rem;
  width: min(100%, 640px);
}

.gateway-manual-row[hidden] {
  display: none;
}

#gateway-manual-input {
  padding: 8px 12px;
  font-size: .85rem;
  min-width: 180px;
  flex: 1 1 260px;
}

#gateway-manual-input:focus {
  outline: none;
  border-color: var(--accent-color);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent-color) 15%, transparent);
}

#gateway-manual-save,
#gateway-manual-cancel {
  background: var(--button-bg);
  border: 1px solid var(--border-color);
  color: var(--primary-text);
  border-radius: 8px;
  padding: 8px 10px;
  font-size: .8rem;
  cursor: pointer;
}

.debug-panel {
  position: fixed;
  right: 12px;
  bottom: 86px;
  z-index: 90;
  border: 0;
  background: transparent;
  padding: 0;
  font-size: .78rem;
}

.debug-panel summary {
  list-style: none;
  cursor: pointer;
  color: var(--primary-text);
  font-weight: 600;
  border: 1px solid var(--border-color);
  border-radius: 999px;
  background: color-mix(in srgb, var(--surface-color) 88%, black);
  box-shadow: 0 10px 26px rgba(0,0,0,.28);
  padding: 7px 11px;
}

#debug-copy-btn {
  display: block;
  width: 100%;
  margin: 6px 0 4px;
  padding: 8px;
  font: 600 .78rem/1 inherit;
  color: var(--primary-text);
  background: color-mix(in srgb, var(--surface-color) 88%, black);
  border: 1px solid var(--border-color);
  border-radius: 8px;
}

/* Selectable on touch: several webviews suppress long-press selection on
   generic blocks, and the copy fallback needs a real selection to act on. */
#debug-log {
  -webkit-user-select: text;
  user-select: text;
}

.debug-panel summary::-webkit-details-marker {
  display: none;
}

#debug-log {
  position: absolute;
  right: 0;
  bottom: calc(100% + 8px);
  width: min(680px, calc(100vw - 24px));
  max-height: min(360px, 52vh);
  margin: 0;
  overflow: auto;
  white-space: pre-wrap;
  color: var(--secondary-text);
  background: color-mix(in srgb, var(--surface-color) 94%, black);
  border: 1px solid var(--border-color);
  border-radius: 10px;
  box-shadow: 0 18px 42px rgba(0,0,0,.34);
  padding: 10px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
}

.collapsible-section {
  border-bottom: 1px solid var(--border-color);
  background: rgba(0,0,0,.04);
  max-height: 800px;
  overflow-y: auto;
  transition: background .3s ease;
}
.collapsible-section summary {
  padding: 1rem 1.5rem;
  font-weight: 600;
  cursor: pointer;
  color: var(--secondary-text);
  display: flex;
  align-items: center;
  transition: all .3s ease;
  user-select: none;
}
.collapsible-section summary:hover {
  background: rgba(0,0,0,.08);
  color: var(--primary-text);
}
.collapsible-section[open] summary {
  color: var(--accent-color);
  background: rgba(0,0,0,.06);
}
.collapsible-section summary input[type="checkbox"] { margin-right: .6rem; pointer-events: all; }

.registry-content, .advanced-options-content {
  padding: 1.25rem 1.5rem;
  display: flex;
  flex-direction: column;
  gap: 1rem;
  transition: opacity .3s ease;
  background: rgba(0,0,0,.02);
}
.advanced-options-content.disabled { opacity: .4; pointer-events: none; }

.registry-form-grid {
  display: grid;
  grid-template-columns: 1fr 2fr;
  gap: 1rem;
  margin-bottom: 1.25rem;
}
.registry-options-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  align-items: flex-end;
  padding-bottom: 1rem;
  border-bottom: 1px solid var(--border-color);
}

.registry-options-grid .registry-search-button {
  margin-left: auto;
}
.advanced-options-content { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px,1fr)); align-items: center; }

.form-group, .form-group-small, .form-group-checkbox { display: flex; flex-direction: column; gap: .5rem; }
.form-group-checkbox { flex-direction: row; align-items: center; gap: .5rem; padding-bottom: 8px; }
.advanced-options-content .form-group-checkbox { padding-bottom: 0; }
.form-group label, .form-group-small label {
  font-size: .85rem;
  color: var(--secondary-text);
  font-weight: 600;
  letter-spacing: 0.3px;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

/* Clean input styling for registry */
.registry-modal-content .form-group input,
.registry-modal-content .form-group-small input {
  width: 100%;
  background: var(--input-bg-color);
  border: 1.5px solid var(--input-border-color);
  color: var(--primary-text);
  border-radius: 10px;
  padding: 12px 14px;
  font-size: .9rem;
  transition: all .2s ease;
}

.registry-modal-content .form-group input:focus,
.registry-modal-content .form-group-small input:focus {
  outline: none;
  border-color: var(--accent-color);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent-color) 20%, transparent);
}

.registry-modal-content .form-group input::placeholder {
  color: var(--secondary-text);
  opacity: 0.7;
}

/* Checkbox styling */
.registry-modal-content .form-group-checkbox {
  background: transparent;
  padding: 0;
  border: none;
  cursor: pointer;
  padding-bottom: 0;
}

.registry-modal-content .form-group-checkbox input[type="checkbox"] {
  width: 16px;
  height: 16px;
  accent-color: var(--accent-color);
  cursor: pointer;
}

.registry-modal-content .form-group-checkbox label {
  font-size: .85rem;
  font-weight: 500;
  cursor: pointer;
  color: var(--secondary-text);
}

.form-group label, .form-group-small label, .form-group-checkbox label {
  font-size: .85rem;
  color: var(--secondary-text);
  font-weight: 600;
  letter-spacing: 0.3px;
}
.form-group input, .form-group-small input {
  width: 100%;
  background: var(--input-bg-color);
  border: 1.5px solid var(--input-border-color);
  color: var(--primary-text);
  border-radius: 8px;
  padding: 10px 14px;
  font-size: .9rem;
  transition: all .3s ease;
  box-shadow: 0 2px 4px rgba(0,0,0,.05);
}
.form-group input:focus, .form-group-small input:focus {
  outline: none;
  border-color: var(--accent-color);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent-color) 20%, transparent),
              0 4px 12px rgba(0,0,0,.1);
  transform: translateY(-1px);
}

/* Search button */
.registry-search-button {
  background: var(--accent-color);
  color: #fff;
  border: none;
  padding: 12px 24px;
  border-radius: 10px;
  cursor: pointer;
  font-weight: 600;
  font-size: .9rem;
  transition: all .2s ease;
  display: flex;
  align-items: center;
  justify-content: center;
}

.registry-search-button:hover {
  filter: brightness(1.1);
  transform: translateY(-1px);
}

.registry-search-button:active {
  transform: translateY(0);
}
#registry-results {
  padding: 0;
  max-height: 500px;
  overflow-y: auto;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1rem;
}
#registry-results::-webkit-scrollbar { width: 6px; }
#registry-results::-webkit-scrollbar-thumb { background: var(--scrollbar-thumb-color); border-radius: 3px; }

@media (max-width: 900px) {
  #registry-results { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 600px) {
  .registry-form-grid {
    grid-template-columns: 1fr;
    gap: .85rem;
  }

  .registry-options-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: .75rem;
  }

  .registry-options-grid .form-group-checkbox,
  .registry-options-grid .registry-search-button {
    grid-column: 1 / -1;
  }

  .registry-options-grid .registry-search-button {
    width: 100%;
    margin-left: 0;
  }

  #registry-results { grid-template-columns: 1fr; }
}

@media (max-width: 1024px) {
  /* NB: #agent-url-input + the agent picker are intentionally NOT here -- they
     stay at the smaller picker size. Zoom is disabled (user-scalable=no), so
     the 16px iOS no-zoom trick isn't needed for them. */
  #message-text,
  #agent-gateway-select,
  #gateway-manual-input,
  #theme-selector,
  .form-group input,
  .form-group-small input,
  #registry-query-input,
  #registry-url-input,
  #num-results-input,
  #distance-threshold-input {
    font-size: 16px !important;
  }
}

/* Result cards */
.registry-item {
  display: flex;
  flex-direction: column;
  gap: .75rem;
  padding: 1.25rem;
  background: var(--agent-bubble);
  border-radius: 12px;
  border: 1px solid var(--border-color);
  transition: all .2s ease;
}

.registry-item:hover {
  border-color: var(--accent-color);
  transform: translateY(-2px);
  box-shadow: 0 4px 12px rgba(0,0,0,.1);
}

.registry-item-content {
  flex: 1;
  text-align: left;
  display: flex;
  flex-direction: column;
  gap: .5rem;
}

.registry-item h4 {
  margin: 0;
  font-size: .95rem;
  font-weight: 600;
  color: var(--primary-text);
  text-align: left;
  line-height: 1.3;
}

.registry-item p {
  margin: 0;
  font-size: .8rem;
  color: var(--secondary-text);
  line-height: 1.4;
  text-align: left;
  flex: 1;
}

.registry-item code {
  background: rgba(0,0,0,.15);
  border-radius: 6px;
  font-size: .75rem;
  padding: 6px 10px;
  display: block;
  margin-top: auto;
  word-break: break-all;
  color: var(--secondary-text);
}

.registry-item-error, .registry-item-status {
  text-align: center;
  padding: 2rem;
  font-size: .9rem;
  color: var(--secondary-text);
  grid-column: 1 / -1;
}

.registry-item-error {
  color: var(--error-color);
}

/* Use Agent button */
.use-agent-btn {
  background: var(--accent-color);
  color: #fff;
  border: none;
  padding: 10px 16px;
  border-radius: 8px;
  cursor: pointer;
  font-weight: 600;
  font-size: .85rem;
  transition: all .2s ease;
  width: 100%;
  text-align: center;
}

.use-agent-btn:hover {
  filter: brightness(1.1);
  transform: translateY(-1px);
}

/* Remove Agent button */
.remove-agent-btn {
  background: transparent;
  color: var(--error-color);
  border: 1.5px solid var(--error-color);
  padding: 10px 16px;
  border-radius: 8px;
  cursor: pointer;
  font-weight: 600;
  font-size: .85rem;
  transition: all .2s ease;
  width: 100%;
  text-align: center;
}

.remove-agent-btn:hover {
  background: var(--error-color);
  color: #fff;
}

#chat-box {
  flex: 1;
  padding: 1.15rem clamp(.85rem, 2vw, 1.5rem);
  overflow-y: auto;
  scroll-behavior: smooth;
  display: flex;
  flex-direction: column;
  gap: .55rem;
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--surface-color) 96%, var(--bg-color)), var(--surface-color));
}
#chat-box::-webkit-scrollbar { width: 6px; }
#chat-box::-webkit-scrollbar-track {
  background: transparent;
}
#chat-box::-webkit-scrollbar-thumb {
  background: var(--scrollbar-thumb-color);
  border-radius: 3px;
}
#chat-box::-webkit-scrollbar-thumb:hover {
  background: var(--accent-color);
}

@keyframes fadeIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }

@keyframes typingDot {
  0%, 60%, 100% { transform: translateY(0); opacity: 0.7; }
  30% { transform: translateY(-10px); opacity: 1; }
}

.typing-indicator {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 12px 18px;
  background: var(--agent-bubble);
  border-radius: 18px;
  border-bottom-left-radius: 6px;
  border: 1px solid rgba(255,255,255,.05);
  box-shadow: 0 2px 8px rgba(0,0,0,.08);
  margin: 6px 0;
  align-self: flex-start;
  position: relative;
}

.typing-indicator::before {
  content: '';
  position: absolute;
  bottom: 0;
  left: -8px;
  width: 20px;
  height: 20px;
  background: var(--agent-bubble);
  border: 1px solid rgba(255,255,255,.05);
  border-bottom-right-radius: 16px;
  transform: translateX(10px);
  z-index: -1;
}

.typing-indicator .dot {
  width: 8px;
  height: 8px;
  background: var(--secondary-text);
  border-radius: 50%;
  animation: typingDot 1.4s infinite;
}

.typing-indicator .dot:nth-child(2) {
  animation-delay: 0.2s;
}

.typing-indicator .dot:nth-child(3) {
  animation-delay: 0.4s;
}

.typing-status {
  margin-left: 8px;
  color: var(--secondary-text);
  font-size: .82rem;
  white-space: nowrap;
}

.pdf-viewer-wrapper {
  width: 100%;
  max-width: 100%;
  max-height: min(78vh, 820px);
  overflow: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  border: 1px solid var(--border-color);
  border-radius: 12px;
  background: #111827;
  /* Isolate paint so scrolling the main chat past this element doesn't repaint
     the (large) canvas pages inside it. NOTE: do NOT add `will-change: transform`
     here -- promoting this scrollable area (with many stacked megapixel canvases)
     to a persistent GPU layer makes constrained webviews (z-up / WKWebView /
     Android WebView) thrash the layer, which shows up as a whole-page blink.
     `contain: paint` gives the isolation without the oversized GPU layer. */
  contain: paint;
  /* pan both ways once zoomed; pinch is handled by renderPdfWithPdfjs */
  touch-action: pan-x pan-y;
}

.pdf-canvas-container {
  /* width is set by renderPdfWithPdfjs (the card's width x zoom); the wrapper
     scrolls */
  background: #fff;
  /* No will-change here either (see .pdf-viewer-wrapper) -- it caused the
     webview page-blink when a PDF was on screen. */
  contain: paint;
}

.pdf-zoom-bar {
  position: sticky;
  top: 0;
  left: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 6px;
  padding: 6px 8px;
  background: rgba(17, 24, 39, 0.92);
  border-bottom: 1px solid rgba(255, 255, 255, 0.12);
}

.pdf-zoom-bar .pptx-nav-btn {
  min-width: 36px;
  min-height: 32px;
}

.pdf-zoom-level {
  min-width: 48px;
  color: #f9fafb;
  font-size: 0.85rem;
  text-align: center;
}

/* Full screen: renderPdfWithPdfjs moves the wrapper to <body> first. */
.pdf-viewer-wrapper.pdf-fullscreen {
  position: fixed;
  inset: 0;
  z-index: 10000;
  max-height: none;
  margin: 0 !important;
  border: 0;
  border-radius: 0;
  padding-top: env(safe-area-inset-top);
}

.pdf-canvas-page {
  display: block;
  border-bottom: 1px solid #e5e7eb;
}

.pdf-canvas-page:last-child {
  border-bottom: none;
}

.pdf-loading, .pdf-load-error {
  padding: 24px 16px;
  text-align: center;
  color: #9ca3af;
  font-size: 14px;
}

.pdf-viewer-frame {
  display: block;
  width: 100%;
  min-width: 680px;
  height: min(76vh, 800px);
  border: 0;
  background: #fff;
}

@media (max-width: 768px) {
  .pdf-viewer-wrapper {
    max-height: 70vh;
  }

  .pdf-viewer-frame {
    min-width: 100%;
    height: 68vh;
  }
}



/* Make sure the wrapper doesn’t enforce center alignment */
.pptx-preview {
  text-align: left !important;
  width: 100%;
  max-width: 100%;
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  position: relative;
  box-sizing: border-box;
  padding-bottom: 8px;
}

.pptx-preview #all_slides_warpper,
.pptx-preview .slides {
  margin-left: auto !important;
  margin-right: auto !important;
}

.pptx-preview .slide .slide-prgrph,
.pptx-preview .slide div.content,
.pptx-preview .slide div.diagram-content,
.pptx-preview .slide span,
.pptx-preview .slide p,
.pptx-zoom .slide .slide-prgrph,
.pptx-zoom .slide div.content,
.pptx-zoom .slide div.diagram-content,
.pptx-zoom .slide span,
.pptx-zoom .slide p {
  white-space: normal !important;
  overflow-wrap: break-word !important;
  word-break: normal !important;
  word-wrap: break-word !important;
  hyphens: none;
}

.pptx-preview .slide .slide-prgrph,
.pptx-zoom .slide .slide-prgrph {
  display: block !important;
  max-width: 100% !important;
}

.pptx-preview .slides-toolbar,
.pptx-preview #slides-full-screen,
.pptx-preview #slides-play-pause,
.pptx-preview #slides-prev,
.pptx-preview #slides-next {
  display: none !important;
}

.message.rich-file-message {
  display: block;
  width: min(100%, 1000px);
  max-width: min(100%, 1000px);
  overflow: visible;
  box-sizing: border-box;
}

.message.agent-message.rich-file-message {
  width: min(100%, 1000px);
  max-width: min(100%, 1000px);
}

.message.pptx-message,
.message.pdf-message {
  align-self: stretch;
}

/* A message holding a PDF viewer or a PPTX card takes the chat's width. Agent
   bubbles are width: fit-content, and both viewers fit their pages to the
   card's width -- inside a fit-content bubble that is circular and the viewer
   collapsed to the width of its toolbar. (:has also covers planner messages,
   which carry files in their artifact list.) */
.message.agent-message:has(.pdf-viewer-wrapper),
.message.agent-message:has(.pptx-card) {
  width: min(100%, 1000px);
  max-width: min(100%, 1000px);
  align-self: stretch;
  box-sizing: border-box;
}

.pptx-card {
  background: var(--surface-color);
  border: 1px solid var(--border-color);
  border-radius: 10px;
  overflow: hidden;
}

.pptx-card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 12px;
  border-bottom: 1px solid var(--border-color);
}

.pptx-card-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 0 0 auto;
  flex-wrap: wrap;
  justify-content: flex-end;
}

.pptx-card-title {
  min-width: 0;
  color: var(--primary-text);
  font-weight: 650;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.pptx-download-link,
.pptx-nav-btn {
  flex: 0 0 auto;
  border: 1px solid var(--border-color);
  border-radius: 8px;
  background: var(--button-bg);
  color: var(--primary-text);
  font: inherit;
  font-size: 0.85rem;
  line-height: 1;
  text-decoration: none;
  padding: 8px 10px;
  cursor: pointer;
}

/* Links in chat messages. Unstyled, they took the browser's default dark blue
   (#0000EE, visited purple): close to unreadable on the dark agent bubble and
   the dark-blue page. :where() keeps this at element weight, so links with a
   class of their own (file buttons, card links) keep their own colors; any
   author color already beats the browser's :visited purple. */
:where(.message) a {
  color: var(--link-color);
  text-decoration: underline;
  text-underline-offset: 2px;
}
:where(.message.user-message) a {
  color: #fff;
}

/* "Save <file>" / "Open PDF": a button like the deck card's Open. */
.file-download-link {
  display: inline-flex;
  align-items: center;
  border: 1px solid var(--border-color);
  border-radius: 8px;
  /* its own surface, so the text contrasts whatever the bubble behind it is */
  background: var(--surface-color);
  color: var(--primary-text);
  font-size: 0.85rem;
  line-height: 1;
  text-decoration: none;
  padding: 8px 10px;
}

.file-download-link:hover {
  filter: brightness(1.15);
}

.file-action-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 10px;
}

.pptx-download-link:hover,
.pptx-nav-btn:hover:not(:disabled) {
  filter: brightness(1.05);
}

.pptx-download-link.disabled,
.file-download-link.disabled {
  cursor: progress;
  opacity: 0.55;
  pointer-events: auto;
}

.pptx-nav-btn:disabled {
  cursor: default;
  opacity: 0.45;
}

.pptx-preview-stage {
  background: #111827;
  padding: 12px;
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  max-height: min(78vh, 860px);
}

.pptx-preview-unavailable {
  color: #f9fafb;
  min-height: 160px;
  display: grid;
  place-items: center;
  text-align: center;
  padding: 20px;
}

.pptx-carousel {
  --pptx-scale: 1;
  --pptx-slide-w: 960px;
  --pptx-slide-h: 540px;
  background: #111827;
  color: #f9fafb;
  outline: none;
}

.pptx-carousel-viewport {
  width: 100%;
  overflow: auto;
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
  position: relative;
  cursor: zoom-in;
  /* pan both ways once zoomed; pinch is handled by the carousel itself */
  touch-action: pan-x pan-y;
  /* A swipe across slide text must not start a selection: the next tap would
     only clear it and never reach the zoom handler. */
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}

.pptx-carousel-slide {
  display: block;
  width: var(--pptx-slide-w);
  height: var(--pptx-slide-h);
}

.pptx-carousel-slide[hidden] {
  display: none;
}

.pptx-carousel-controls .pptx-slide-count {
  min-width: 44px;
}

.pptx-carousel-controls .pptx-nav-btn {
  min-width: 36px;
  min-height: 34px;
}

/* Full-screen single-slide view (openPptxZoom). The page itself cannot zoom
   (user-scalable=no), so the slide is scaled here and the scroller pans both
   ways once it is larger than the screen. Auto margins centre a small slide
   without clipping a large one. */
.pptx-zoom {
  position: fixed;
  inset: 0;
  z-index: 10000;
  display: flex;
  flex-direction: column;
  background: #0b1220;
  color: #f9fafb;
  padding-top: env(safe-area-inset-top);
  padding-left: env(safe-area-inset-left);
  padding-right: env(safe-area-inset-right);
}

.pptx-zoom-bar {
  flex: none;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 8px 10px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.12);
}

.pptx-zoom-bar .pptx-nav-btn {
  min-width: 40px;
  min-height: 36px;
}

.pptx-zoom-spacer {
  flex: 1;
}

.pptx-zoom-scroller {
  flex: 1;
  min-height: 0;
  display: flex;
  overflow: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  touch-action: pan-x pan-y;
}

.pptx-zoom-sizer {
  position: relative;
  flex: none;
  margin: auto;
}

.pptx-zoom .slide,
.pptx-zoom .slide div.block,
.pptx-zoom .slide div.content,
.pptx-zoom .slide div.diagram-content,
.pptx-zoom .slide svg {
  overflow: visible !important;
}

.pptx-slide-stage {
  width: var(--pptx-slide-w);
  height: var(--pptx-slide-h);
  transform-origin: center center;
}

.pptx-slide-stage .slide {
  transform: scale(var(--pptx-scale));
  transform-origin: top left;
}

.pptx-carousel-controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 8px;
}

.pptx-slide-count {
  min-width: 64px;
  color: #f9fafb;
  font-size: 0.85rem;
  text-align: center;
}


.message {
  display: block;
  max-width: min(78%, 840px);
  padding: 10px 14px;
  border-radius: var(--bubble-radius);
  line-height: 1.5;
  font-size: 0.95rem;
  animation: fadeIn 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  box-shadow: 0 2px 8px rgba(0,0,0,.08);
  overflow-wrap: anywhere;
}

.message.user-message {
  background: linear-gradient(135deg, var(--user-bubble-start), var(--user-bubble-end));
  color: #fff;
  border-bottom-right-radius: 6px;
  align-self: flex-end;
  text-align: left;
  margin: 0;
  box-shadow: 0 4px 12px rgba(0,0,0,.15);
  position: relative;
}

.message.user-message::before {
  content: '';
  position: absolute;
  bottom: 0;
  right: -8px;
  width: 20px;
  height: 20px;
  background: var(--user-bubble-end);
  border-bottom-left-radius: 16px;
  transform: translateX(-10px);
  z-index: -1;
}

.message.agent-message {
  background: var(--agent-bubble);
  color: var(--primary-text);
  border-bottom-left-radius: 6px;
  border: 1px solid rgba(255,255,255,.05);
  align-self: flex-start;
  text-align: left;
  margin: 0;
  width: fit-content;
  max-width: min(85%, 840px);
  position: relative;
}

.message.agent-message::before {
  content: '';
  position: absolute;
  bottom: 0;
  left: -8px;
  width: 20px;
  height: 20px;
  background: var(--agent-bubble);
  border: 1px solid rgba(255,255,255,.05);
  border-bottom-right-radius: 16px;
  transform: translateX(10px);
  z-index: -1;
}

/* Clears copy (8-34) and the checkbox (42-58) with a margin. */
.message.copyable-message {
  padding-right: 66px;
}

/* Only messages that actually carry an edit button pay for its width. */
.message.copyable-message.user-message {
  padding-right: 104px;
}

.message-copy-btn,
.message-edit-btn {
  position: absolute;
  top: 7px;
  width: 26px;
  height: 26px;
  border: 1px solid color-mix(in srgb, var(--border-color) 85%, transparent);
  border-radius: 8px;
  background: color-mix(in srgb, var(--surface-color) 70%, transparent);
  color: var(--secondary-text);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transition: opacity .2s ease, color .2s ease, border-color .2s ease, background .2s ease;
}

.message-copy-btn {
  right: 8px;
}

/* The edit button exists only on the user's own messages (renderMessage adds
   it under `msg.type === 'user-message'`), so its slot cannot be the fixed
   offset everything else is measured from -- on an agent reply that slot is
   simply empty, and the checkbox floated 42px from the copy button with
   nothing in between.

   Order from the right edge is now copy, checkbox, edit, each packed against
   the last, so the checkbox moves left only when an edit button is really
   there to make room for. */
.message-edit-btn {
  right: 70px;
}

.message-select-checkbox {
  position: absolute;
  top: 12px;
  /* Copy occupies 8-34; this sits immediately beside it. */
  right: 42px;
  width: 16px;
  height: 16px;
  accent-color: var(--accent-color);
  cursor: pointer;
  opacity: .85;
}

.message-copy-btn svg,
.message-edit-btn svg {
  width: 15px;
  height: 15px;
}

.message.copyable-message:hover .message-copy-btn,
.message.copyable-message:hover .message-edit-btn,
.message.copyable-message:focus-within .message-copy-btn,
.message.copyable-message:focus-within .message-edit-btn {
  opacity: 1;
}

.message-copy-btn:hover,
.message-edit-btn:hover {
  color: var(--primary-text);
  border-color: var(--accent-color);
  background: color-mix(in srgb, var(--accent-color) 14%, var(--surface-color));
}

.message.user-message .message-copy-btn,
.message.user-message .message-edit-btn {
  color: rgba(255, 255, 255, .72);
  border-color: rgba(255, 255, 255, .2);
  background: rgba(0, 0, 0, .16);
}

.message.user-message .message-copy-btn:hover,
.message.user-message .message-edit-btn:hover {
  color: #fff;
  border-color: rgba(255, 255, 255, .42);
  background: rgba(0, 0, 0, .26);
}

@media (hover: none) {
  .message-copy-btn,
  .message-edit-btn {
    opacity: 1;
  }
}

.agent-message img, .agent-message video { max-width: 100%; display: block; border-radius: 12px; }

.message img, .agent-image img { cursor: zoom-in; }

/* Full-screen image viewer -- pinch/double-tap zoom is handled here via JS
   + CSS transform, scoped to just this overlay (touch-action: none) instead
   of the page-wide pinch-zoom a plain inline <img> triggers via the
   viewport meta tag (maximum-scale=5.0, user-scalable=yes). */
.image-viewer-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, .92);
  display: none;
  align-items: center;
  justify-content: center;
  z-index: 3000;
  touch-action: none;
  overscroll-behavior: contain;
}

.image-viewer-overlay.active {
  display: flex;
}

.image-viewer-close {
  position: absolute;
  top: 16px;
  right: 16px;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: rgba(255, 255, 255, .12);
  border: none;
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  z-index: 1;
}

.image-viewer-close:hover { background: rgba(255, 255, 255, .22); }
.image-viewer-close svg { width: 22px; height: 22px; }

.image-viewer-stage {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  touch-action: none;
}

.image-viewer-img {
  max-width: 92vw;
  max-height: 92vh;
  object-fit: contain;
  user-select: none;
  -webkit-user-drag: none;
  will-change: transform;
  transform-origin: center center;
  cursor: grab;
  touch-action: none;
}

.inline-media-wrapper {
  display: flex;
  justify-content: center;
  margin: 1rem 0;
  width: 100%;
}

.agent-message .inline-media-embed {
  width: min(100%, 720px);
  max-height: 70vh;
  border-radius: 12px;
  border: 1px solid var(--border-color);
  background: #000;
}

.agent-message audio.inline-media-embed {
  width: min(100%, 560px);
  max-height: none;
  background: transparent;
}

.agent-message iframe.inline-media-embed {
  aspect-ratio: 16 / 9;
  height: auto;
  border: 1px solid var(--border-color);
}

/* Override the base .inline-media-wrapper's flex-centering: make the
   wrapper's own box match the iframe's rendered width (instead of
   spanning the full message width with the iframe centered inside it),
   so the absolutely-positioned fullscreen button below lands at the
   iframe's actual top-right corner. */
.iframe-embed-wrapper {
  position: relative;
  display: block;
  width: min(100%, 720px);
  margin: 1rem auto;
}

.iframe-embed-wrapper .video-fullscreen-btn {
  top: 8px;
  right: 8px;
}

/* CSS-only "fake fullscreen" for iframe embeds -- deliberately not using
   element.requestFullscreen(). On the WebView this was tested on, exiting
   native fullscreen on an <iframe> (unlike a generated <video>) left a
   stale layer intercepting touches over the entire page that no
   repaint/reflow nudge could clear -- consistent with a native backdrop
   the WebView failed to tear down. This expands the wrapper itself via
   plain CSS instead, entirely within the page's own DOM, so there is
   nothing native left behind to fail to clean up. */
.iframe-embed-wrapper.iframe-fake-fullscreen {
  position: fixed;
  inset: 0;
  width: 100vw;
  height: 100vh;
  max-width: none;
  margin: 0;
  z-index: 3000;
  background: #000;
  display: flex;
  align-items: center;
  justify-content: center;
}

.iframe-embed-wrapper.iframe-fake-fullscreen iframe {
  width: 100% !important;
  height: 100% !important;
  max-height: none !important;
  aspect-ratio: unset !important;
  border: none !important;
  border-radius: 0 !important;
}

.iframe-embed-wrapper.iframe-fake-fullscreen .video-fullscreen-btn {
  display: none;
}

.iframe-fake-fullscreen-close {
  position: fixed;
  top: 16px;
  right: 16px;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: rgba(255, 255, 255, .12);
  border: none;
  color: #fff;
  display: none;
  align-items: center;
  justify-content: center;
  z-index: 3001;
  cursor: pointer;
}

.iframe-fake-fullscreen-close.active { display: flex; }
.iframe-fake-fullscreen-close svg { width: 22px; height: 22px; }
.iframe-fake-fullscreen-close:hover { background: rgba(255, 255, 255, .22); }

.message.status,
.message.error {
  display: block;
  width: fit-content;
  margin: .4rem auto;
  text-align: center;
  font-size: 0.85rem;
  padding: 8px 16px;
  border-radius: 16px;
  background: rgba(0,0,0,0.08);
  color: var(--secondary-text);
  border: 1px solid var(--border-color);
  box-shadow: 0 2px 6px rgba(0,0,0,.05);
  font-weight: 500;
}

.message.error {
  background: var(--error-bg-color);
  color: var(--error-color);
  border-color: var(--error-color);
  box-shadow: 0 2px 8px color-mix(in srgb, var(--error-color) 20%, transparent);
}

.agent-image {
  align-self: flex-start;
  margin: 0;
  padding: 8px;
  background: var(--agent-bubble);
  border-radius: 16px;
  max-width: 72%;
  border: 1px solid rgba(255,255,255,.05);
  box-shadow: 0 4px 12px rgba(0,0,0,.1);
}
.agent-image img, .agent-image video {
  max-width: 100%;
  display: block;
  border-radius: 12px;
  box-shadow: 0 2px 8px rgba(0,0,0,.15);
}

.video-wrap {
  position: relative;
  display: inline-block;
  max-width: 100%;
}

.video-fullscreen-btn {
  position: absolute;
  top: 8px;
  right: 8px;
  width: 34px;
  height: 34px;
  border-radius: 8px;
  background: rgba(0, 0, 0, .55);
  border: none;
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  z-index: 2;
}

.video-fullscreen-btn:hover { background: rgba(0, 0, 0, .75); }
.video-fullscreen-btn svg { width: 18px; height: 18px; }

.message p, .message ul, .message ol, .message pre, .message blockquote { margin: .25rem 0; }
.message > :first-child { margin-top: 0; }
.message > :last-child  { margin-bottom: 0; }

.message pre {
  background: rgba(0,0,0,.3);
  padding: 12px 16px;
  border-radius: 10px;
  white-space: pre-wrap;
  word-wrap: break-word;
  font-size: .85em;
  max-height: 220px;
  overflow: auto;
  border: 1px solid rgba(255,255,255,.05);
  box-shadow: inset 0 2px 4px rgba(0,0,0,.2);
  font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
  line-height: 1.5;
}
.message pre::-webkit-scrollbar {
  width: 6px;
  height: 6px;
}
.message pre::-webkit-scrollbar-thumb {
  background: var(--scrollbar-thumb-color);
  border-radius: 3px;
}
.message code {
  font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
  background: rgba(0,0,0,.3);
  padding: 3px 6px;
  border-radius: 5px;
  font-size: .9em;
  border: 1px solid rgba(255,255,255,.05);
}

.message table {
  width: max-content;
  max-width: 100%;
  border-collapse: collapse;
  display: block;
  overflow-x: auto;
  white-space: nowrap;
}

.message th,
.message td {
  padding: 6px 10px;
  border-bottom: 1px solid var(--border-color);
  vertical-align: top;
}

.agent-html-card {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  max-width: min(100%, 420px);
  padding: 16px;
  border-radius: 12px;
  border: 1px solid var(--border-color);
  background: color-mix(in srgb, var(--surface-color) 88%, #fff 12%);
}

.agent-html-card-auth {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: #fff;
  border-color: rgba(255,255,255,.14);
}

.agent-html-card-skills {
  background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
  color: #fff;
  border-color: rgba(255,255,255,.14);
}

.agent-html-card-waiting {
  background: #f0f9ff;
  color: #0369a1;
  border-color: #bae6fd;
}

.agent-html-card-loading {
  background: color-mix(in srgb, var(--accent-color) 14%, var(--surface-color));
}

.agent-html-card-icon,
.agent-html-card-spinner {
  width: 40px;
  height: 40px;
  border-radius: 999px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.agent-html-card-icon {
  font-size: 20px;
  background: rgba(255,255,255,0.18);
}

.agent-html-card-spinner {
  width: 24px;
  height: 24px;
  border: 3px solid currentColor;
  border-top-color: transparent;
  background: transparent;
  animation: authSpin 1s linear infinite;
}

.agent-html-card-body {
  display: grid;
  gap: 4px;
}

.agent-html-card-title {
  font-size: 14px;
  font-weight: 600;
}

.agent-html-card-subtitle,
.agent-html-card-extra {
  font-size: 12px;
  color: inherit;
  opacity: 0.88;
}

.agent-html-card-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 8px;
}

.agent-html-card-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 140px;
  padding: 10px 14px;
  border-radius: 10px;
  text-decoration: none;
  background: rgba(255,255,255,0.16);
  color: inherit;
  border: 1px solid rgba(255,255,255,0.22);
  font-weight: 600;
}

.agent-html-card-generic .agent-html-card-link,
.agent-html-card-loading .agent-html-card-link,
.agent-html-card-waiting .agent-html-card-link {
  background: var(--accent-color);
  color: #fff;
  border-color: color-mix(in srgb, var(--accent-color) 70%, #fff 30%);
}

.agent-html-card-link:hover {
  filter: brightness(1.04);
}

.auth-required-card {
  display: grid;
  gap: 10px;
  min-width: min(100%, 320px);
}

.auth-required-title {
  font-size: 1rem;
  font-weight: 600;
  color: var(--primary-text);
}

.auth-required-subtitle {
  font-size: .85rem;
  color: var(--secondary-text);
}

.auth-required-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: fit-content;
  min-width: 180px;
  padding: 10px 14px;
  border-radius: 10px;
  text-decoration: none;
  color: #fff;
  background: var(--accent-color);
  border: 1px solid color-mix(in srgb, var(--accent-color) 70%, #fff 30%);
  font-weight: 600;
}

.auth-required-link:hover {
  background: var(--accent-color-hover);
}

.auth-waiting-card {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  min-width: min(100%, 260px);
  padding: 18px 16px;
  border-radius: 12px;
  background: color-mix(in srgb, var(--accent-color) 10%, var(--surface-color));
  border: 1px solid color-mix(in srgb, var(--accent-color) 35%, var(--border-color));
}

.auth-waiting-spinner {
  width: 24px;
  height: 24px;
  border: 3px solid color-mix(in srgb, var(--accent-color) 75%, #fff 25%);
  border-top-color: transparent;
  border-radius: 50%;
  animation: authSpin 1s linear infinite;
}

.auth-waiting-text {
  font-size: .9rem;
  font-weight: 500;
  color: var(--primary-text);
  text-align: center;
}

.skills-loading-card {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  padding: 16px;
  border-radius: 12px;
  background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
  color: #fff;
}

.skills-loading-icon {
  width: 40px;
  height: 40px;
  border-radius: 999px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 20px;
  background: rgba(255,255,255,0.2);
  flex-shrink: 0;
}

.skills-loading-content {
  display: grid;
  gap: 2px;
}

.skills-loading-title {
  font-size: 14px;
  font-weight: 600;
}

.skills-loading-subtitle {
  font-size: 12px;
  color: rgba(255,255,255,0.82);
}

@keyframes authSpin {
  to { transform: rotate(360deg); }
}

#message-form {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: .75rem;
  padding: .85rem 1rem;
  background: color-mix(in srgb, var(--surface-color) 96%, var(--bg-color));
  flex-shrink: 0;
  border-top: 1px solid var(--border-color);
}

.composer-toolbar {
  display: flex;
  align-items: center;
  gap: .5rem;
  flex-wrap: wrap;
  min-width: 0;
}

#message-form .form-input-row {
  display: flex;
  align-items: flex-end;
  gap: .5rem;
  flex: 1;
  min-width: 0;
}
#message-text {
  flex: 1;
  background: var(--input-bg-color);
  border: 1px solid var(--border-color);
  border-radius: 12px;
  outline: none;
  color: var(--primary-text);
  font-family: var(--font-family);
  font-size: .9rem;
  padding: 10px 14px;
  /* Only the focus-ring visuals transition. NOT `all`: autoResizeTextarea
     rewrites `height` on every keystroke, and `transition: all` made the
     webview animate that height change over .2s -- reflowing the chat area
     above it each frame, which showed up as a per-keystroke page blink. */
  transition: border-color .2s ease, box-shadow .2s ease, background .2s ease;
  resize: none;
  min-height: 44px;
  overflow-y: auto;
  line-height: 1.5;
}
#message-text:focus {
  border-color: var(--accent-color);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent-color) 15%, transparent);
}
#message-text::-webkit-scrollbar {
  width: 6px;
}
#message-text::-webkit-scrollbar-thumb {
  background: var(--scrollbar-thumb-color);
  border-radius: 3px;
}

.icon-button {
  background: var(--input-bg-color);
  border: 1px solid var(--border-color);
  cursor: pointer;
  padding: 8px;
  border-radius: 9px;
  color: var(--secondary-text);
  transition: all .2s ease;
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 38px;
  min-height: 38px;
}
.icon-button:hover {
  color: var(--primary-text);
  border-color: var(--accent-color);
  background: var(--input-bg-color);
}
.icon-button:active {
  transform: scale(0.95);
}
.icon-button svg { width: 20px; height: 20px; vertical-align: middle; }

/* Accent buttons in header */
#open-registry-btn,
#send-button {
  background: var(--accent-color);
  border-color: var(--accent-color);
  color: #fff;
}

#open-registry-btn:hover,
#send-button:hover {
  filter: brightness(1.1);
  color: #fff;
  border-color: var(--accent-color);
}

/* Clear chat button */
#clear-chat-btn:hover {
  background: var(--error-bg-color);
  border-color: var(--error-color);
  color: var(--error-color);
}

#history-toggle-bottom-btn { display: none; }

#file-preview {
  display: flex;
  flex-direction: column;
  gap: .5rem;
  background: var(--agent-bubble);
  padding: 10px;
  border-radius: 10px;
  font-size: .8rem;
  /* fit-content sizes to the widest line, and a nowrap file name's narrowest
     possible width is its whole length -- so a long name pushed the box past
     the screen (500px is wider than a phone, and the mobile override only
     starts at 420px). Cap it at the composer's width at every size; the name
     then ellipsizes inside. */
  max-width: min(500px, 100%);
  min-width: 0;
  width: fit-content;
  border: 1px solid var(--border-color);
  align-self: flex-start;
}

#file-list {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: .5rem;
  max-height: 150px; overflow-y: auto;
  min-width: min(280px, 100%);
  max-width: 100%;
}

#file-list::-webkit-scrollbar { width: 4px; }
#file-list::-webkit-scrollbar-thumb { background: var(--scrollbar-thumb-color); border-radius: 2px; }

.file-chip {
  display: flex; align-items: center; gap: .6rem;
  min-width: 0;
  background: var(--surface-color);
  padding: 8px 10px;
  border-radius: 8px;
  border: 1px solid var(--border-color);
  transition: all .2s ease;
}

.file-chip:hover {
  border-color: var(--accent-color);
}

.file-chip-thumbnail {
  width: 40px; height: 40px; flex-shrink: 0;
  border-radius: 6px; object-fit: cover;
  background: var(--bg-color);
  border: 1px solid var(--border-color);
}

.file-chip-icon {
  width: 40px; height: 40px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: var(--bg-color);
  border-radius: 6px;
  border: 1px solid var(--border-color);
}

.file-chip-icon svg {
  width: 22px; height: 22px;
  color: var(--accent-color);
}

.file-chip-info {
  flex: 1; min-width: 0;
  display: flex; flex-direction: column; gap: 2px;
}

.file-chip-name {
  font-size: .85rem; font-weight: 500;
  color: var(--primary-text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

.file-chip-size {
  font-size: .7rem;
  color: var(--secondary-text);
}

.file-chip-remove {
  background: transparent; border: none;
  color: var(--secondary-text);
  cursor: pointer; padding: 4px;
  border-radius: 4px;
  transition: background-color .2s, color .2s;
  flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
}

.file-chip-remove:hover {
  background: var(--error-bg-color);
  color: var(--error-color);
}

.file-chip-remove svg {
  width: 18px; height: 18px;
}

#remove-all-files-button {
  background: transparent; color: var(--error-color);
  border: 1px solid var(--error-color); padding: 5px 10px;
  border-radius: 6px; cursor: pointer; font-weight: 500;
  font-size: .75rem; transition: all .2s ease;
  align-self: flex-end;
  display: flex; align-items: center; gap: 4px;
}

#remove-all-files-button svg {
  width: 14px; height: 14px;
}

#remove-all-files-button:hover {
  background: var(--error-color);
  color: #fff;
}

.modal-overlay {
  position: fixed; inset: 0;
  background: var(--modal-overlay-bg);
  backdrop-filter: none;
  display: flex; justify-content: center; align-items: center;
  z-index: 1000;
  animation: none;
}
.modal-content {
  background: var(--surface-color);
  padding: 1.5rem;
  border-radius: 12px;
  box-shadow: 0 10px 40px rgba(0,0,0,.4);
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  animation: none;
  border: 1px solid var(--border-color);
}

.modal-content:not(.registry-modal-content) {
  text-align: center;
  min-width: 320px;
}
@keyframes slideUp {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: translateY(0); }
}
.modal-content video {
  border-radius: 10px;
  background: #000;
  width: min(80vw, 720px);
  aspect-ratio: 4 / 3;
  object-fit: contain;
  max-width: 80vw;
  max-height: 60vh;
}
.modal-buttons { display: flex; gap: .75rem; justify-content: center; }
.modal-button {
  background: var(--accent-color);
  color: #fff;
  border: none;
  padding: 10px 20px;
  border-radius: 8px;
  cursor: pointer;
  font-weight: 600;
  font-size: .9rem;
  transition: all .2s ease;
}
.modal-button.secondary {
  background: var(--input-bg-color);
  color: var(--primary-text);
  border: 1px solid var(--border-color);
}
.modal-button:hover {
  filter: brightness(1.1);
}
.modal-button.secondary:hover {
  border-color: var(--accent-color);
}
.modal-button:disabled {
  cursor: default;
  opacity: .55;
  filter: none;
}
.modal-button:active {
  transform: scale(0.98);
}

@media (max-width: 768px) {
  .modal-buttons {
    flex-wrap: wrap;
  }
}

/* ===== CLEAN SEARCH MODAL REDESIGN ===== */

.registry-modal-content {
  max-width: 1200px;
  width: 95vw;
  max-height: 90vh;
  overflow-y: auto;
  padding: 0;
  background: var(--surface-color);
  border: 1px solid var(--border-color);
  border-radius: 16px;
  animation: none;
}

#registry-modal {
  backdrop-filter: none;
  animation: none;
}

.modal-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1.25rem 1.5rem;
  border-bottom: 1px solid var(--border-color);
  background: var(--surface-color);
  z-index: 10;
}

.modal-header h2 {
  margin: 0;
  font-size: 1.25rem;
  font-weight: 600;
  color: var(--primary-text);
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

.close-modal-btn {
  background: transparent;
  padding: 8px;
  border-radius: 8px;
  transition: all 0.2s ease;
}

.close-modal-btn:hover {
  background: var(--error-bg-color);
  color: var(--error-color);
}

.registry-modal-content .registry-content {
  padding: 1.5rem;
}

.registry-modal-content #registry-results {
  padding: 0;
  margin-top: 1.5rem;
}

/* Search icon badge in header */
.search-icon-badge {
  width: 36px;
  height: 36px;
  background: var(--accent-color);
  border-radius: 10px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.search-icon-badge svg {
  color: #fff;
}

/* Label icons styling */
.registry-modal-content .form-group label svg,
.registry-modal-content .form-group-small label svg {
  color: var(--accent-color);
  flex-shrink: 0;
}

#audio-status, #video-status { color: var(--secondary-text); }
#audio-status.recording, #video-status.recording { color: var(--error-color); font-weight: 600; }
.hidden { display: none !important; }

@media (max-width: 768px) {
  body {
    padding: 0;
    /* Was overflow:hidden, with JS pinning .app-shell's height/offset via
       visualViewport to keep the focused input above the on-screen keyboard.
       That fought this WebView's own auto-scroll-into-view behavior (each
       compensating shift appeared to trigger another re-pan), causing rapid
       flicker. Letting the document scroll instead hands keyboard avoidance
       entirely to the browser's native, already-correct handling -- no JS
       needed. overscroll-behavior-y prevents rubber-band bounce since there's
       normally nothing to scroll (.app-shell fills the viewport exactly). */
    overflow-y: auto;
    overscroll-behavior-y: contain;
    background: linear-gradient(180deg, #061326 0%, #081a33 42%, #0b1021 100%);
  }

  body,
  .app-shell,
  .chat-main,
  .chat-container {
    background: linear-gradient(180deg, #061326 0%, #081a33 42%, #0b1021 100%);
  }
  .app-shell {
    height: 100dvh;
    min-height: 100dvh;
    max-width: none;
    gap: 0;
    position: relative;
  }
  #history-sidebar {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    height: 100dvh;
    width: min(82vw, 280px);
    min-width: 0;
    border-radius: 0;
    z-index: 160;
    transform: translateX(-100%);
    transition: transform .25s ease;
  }
  #history-sidebar.open { transform: translateX(0); }
  /* The drawer starts at the physical top of the screen, so its header must clear
     the camera / status bar the same way .chat-header does (same expression, see
     there for how it was tuned) -- otherwise "+" (new chat) sits under the notch. */
  #history-sidebar .history-header {
    padding-top: calc(env(safe-area-inset-top, 0px) * 0.684 + .633rem);
  }
  #history-close-btn {
    display: inline-flex;
  }
  .chat-main { width: 100%; }
  .chat-container {
    height: 100dvh;
    min-height: 0;
    border-radius: 0;
    border-left: 0;
    border-right: 0;
    border-bottom: 0;
    background: linear-gradient(180deg, rgba(6,19,38,.98) 0%, rgba(8,20,42,.96) 48%, #0b1021 100%);
    overflow: visible;
  }
  .chat-header {
    /* The inset is scaled, not taken whole. The OS reports the full band it
       considers unsafe, but a control only has to clear what is actually
       drawn there, and the last stretch of that band was reading as dead
       space. The factor and the constant were solved from two devices that
       had been judged by eye: a Galaxy S21 sitting right at 28.5px from the
       top, and an iPhone 17 Pro Max at 50.4px.

       Two devices fit two unknowns exactly, so treat both numbers as tuned
       rather than derived -- they reproduce those two judgements and
       interpolate between them, nothing more. What does not depend on the tuning is the shape:
       a device with no notch pays almost nothing, and a device with a big one
       pays proportionally. The old flat value could not do either.

       Was a flat 66px, chosen for the worst device and paid for by every
       device. Measured: the first row sat 67px down while an iPhone 17 Pro Max
       needed 0 and a Galaxy S21 needed 27 -- 67px and 40px of nothing.
       env() asks the device instead of guessing, and the .55rem on top is the
       breathing room, not clearance.

       The inset is NOT optional here. A first attempt used a flat .55rem and
       put the gateway picker under the S21's status bar and camera cut-out:
       unlike inset-bottom, which that webview reports for a navigation bar its
       viewport already excludes, inset-top is real -- the viewport does start
       at the physical top of the screen. The 66px had been hiding that by
       accident, which is why the top had always looked fine. */
    padding: calc(env(safe-area-inset-top, 0px) * 0.684 + .633rem) .7rem .65rem;
    align-items: stretch;
    gap: .42rem;
    background: linear-gradient(180deg, rgba(7,18,38,.92), rgba(10,20,40,.74));
    border-bottom-color: rgba(125,211,252,.18);
    position: relative;
    overflow: visible;
    z-index: 70;
  }
  .chat-header::before {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;
    background: linear-gradient(120deg, transparent 16%, rgba(59,130,246,.18) 17%, transparent 25%, transparent 74%, rgba(147,197,253,.14) 75%, transparent 84%);
    opacity: .42;
  }
  .chat-header h1 {
    display: none;
  }
  .chat-header .desktop-title,
  .chat-header .mobile-title {
    display: none;
  }

  .desktop-nav-action {
    display: none !important;
  }

  #history-toggle-bottom-btn {
    display: flex;
    position: fixed;
    /* Same expression as the header's padding-top, so the button lands on the
       first row rather than above it -- and clears the cut-out with it. */
    top: calc(env(safe-area-inset-top, 0px) * 0.684 + .633rem);
    left: .7rem;
    width: 38px;
    height: 38px;
    min-width: 38px;
    min-height: 38px;
    align-items: center;
    justify-content: center;
    border-radius: 10px;
    border: 1px solid rgba(125,211,252,.28);
    background: rgba(15,23,42,.72);
    color: color-mix(in srgb, var(--secondary-text) 62%, #bae6fd 38%);
    box-shadow: inset 0 1px 0 rgba(255,255,255,.08), 0 8px 18px rgba(2,8,23,.2);
    backdrop-filter: blur(10px);
    z-index: 120;
  }

  #history-toggle-bottom-btn svg {
    width: 20px;
    height: 20px;
  }

  .controls-wrapper {
    width: 100%;
    flex: 0 0 100%;
    order: 1;
    display: grid;
    grid-template-columns: minmax(0, 1fr) 38px;
    align-items: center;
    gap: .35rem;
    padding-top: 0;
    margin-top: 0;
    border-top: 0;
    position: relative;
    z-index: 1;
  }

  /* The two floating buttons now share this line instead of owning a strip
     above it, so the first row steps around them: 38px for the button plus the
     .35rem gap the grid uses elsewhere. Only this row -- the one below keeps
     the full width. */
  .controls-wrapper > .gateway-url-group {
    padding-left: calc(38px + .35rem);
    padding-right: calc(38px + .35rem);
  }
  .controls-wrapper > .icon-button,
  .controls-wrapper > a.icon-button {
    width: 100%;
  }

  .controls-wrapper > .icon-button,
  .controls-wrapper > a.icon-button,
  .nav-menu-button,
  .theme-selector-group label {
    background: rgba(15,23,42,.58);
    border-color: rgba(125,211,252,.24);
    color: color-mix(in srgb, var(--secondary-text) 70%, #bae6fd 30%);
    border-radius: 10px;
    box-shadow: inset 0 1px 0 rgba(255,255,255,.08), 0 8px 18px rgba(2,8,23,.2);
    backdrop-filter: blur(10px);
  }

  .agent-url-group label {
    color: var(--secondary-text);
    text-shadow: none;
  }

  #agent-gateway-select,
  #agent-url-input {
    background: rgba(15,23,42,.62);
    border-color: rgba(125,211,252,.22);
  }

  .mobile-agent-mark {
    display: none;
  }

  .nav-menu {
    display: block;
    position: fixed;
    top: calc(env(safe-area-inset-top, 0px) * 0.684 + .633rem);
    right: .7rem;
    grid-column: auto;
    order: 1;
    justify-self: auto;
    z-index: 120;
  }

  .nav-menu-button {
    border-radius: 10px;
    width: 38px;
    height: 38px;
    min-width: 38px;
    min-height: 38px;
  }

  .nav-menu-panel {
    position: fixed;
    top: 62px;
    right: .7rem;
    min-width: 178px;
    z-index: 121;
  }

  .agent-url-group {
    display: grid;
    grid-template-columns: 72px minmax(0, 1fr);
    align-items: center;
    grid-column: 1 / -1;
    order: 10;
    gap: .35rem;
    width: 100%;
    min-width: 0;
  }
  .agent-url-group label {
    width: auto;
    min-width: 0;
    font-size: .76rem;
  }
  #agent-url-input {
    width: 100%;
    max-width: none;
    min-width: 0;
  }
  .agent-address-group {
    width: 100%;
    max-width: none;
  }
  /* Stay flex (not grid) so the picker and the URL field are both flex:1 1 0
     and render at the same width; grid gave the 1fr to one and collapsed the
     other once the agent picker was added to this row. */
  .agent-url-input-row {
    display: flex;
    flex-wrap: nowrap;
    align-items: center;
    gap: .35rem;
  }

  /* The spacer existed to line this row's right edge up with the 38px button
     column of the row above. That row now insets itself past the floating
     buttons instead, so the spacer only held 38px of nothing between the
     search button and the edge -- and kept the button from sitting under the
     menu button it belongs beside. */
  .agent-url-input-row::after {
    display: none;
  }

  /* Neither row spends 72px on a word. On a 360px screen that column was a
     fifth of the agent row and, after this row insets past the floating
     buttons, 29% of the gateway row -- which left its <select> 86px, narrower
     than the two buttons beside it.

     The names survive: the agent field carries a placeholder, and the gateway
     <select> carries aria-label and title, so assistive technology and a
     long-press both still say "Gateway". What a select shows when collapsed is
     the chosen gateway's own address, which is not something a caption makes
     clearer. */
  .agent-address-group {
    grid-template-columns: minmax(0, 1fr);
  }

  .agent-address-group > label {
    display: none;
  }

  /* The gateway keeps a caption, as an icon. The word cost 72px -- 29% of this
     row once it insets past the floating buttons, leaving its <select> 86px,
     narrower than the two buttons next to it. A 22px mark says the same thing
     in a third of the space, and the word stays in the DOM for screen readers
     rather than being replaced by an aria-label. */
  .gateway-url-group {
    grid-template-columns: 22px minmax(0, 1fr);
  }

  .gateway-label {
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--secondary-text);
  }

  .gateway-label-icon {
    display: block;
    width: 20px;
    height: 20px;
  }

  /* Reachable by assistive technology, absent from the layout. */
  .gateway-label-text {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
  .gateway-url-group {
    order: 9;
    width: 100%;
    max-width: none;
  }
  /* One button, not two. Add and remove are rare, and on a 360px screen the
     pair was wider than the picker beside them. They are revealed by the
     toggle and the column count changes with them, so the picker gets the
     space back whenever they are closed -- which is nearly always. */
  .gateway-select-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 38px;
    gap: .35rem;
    min-width: 0;
  }

  /* + and - drop BELOW the toggle rather than growing the row sideways, so the
     picker keeps its full width whether they are open or shut. Taken out of
     the grid entirely: as grid items they would have re-divided the row. */
  .gateway-select-row {
    position: relative;
  }

  .gateway-select-row > .gateway-add-button,
  .gateway-select-row > .gateway-delete-button {
    display: none;
    position: absolute;
    right: 0;
    width: 38px;
    min-width: 38px;
    height: 38px;
    z-index: 130;
    box-shadow: 0 8px 20px rgba(2, 8, 23, .45);
  }

  .gateway-select-row.gateway-actions-open > .gateway-add-button {
    display: inline-flex;
    top: calc(100% + .35rem);
  }

  .gateway-select-row.gateway-actions-open > .gateway-delete-button {
    display: inline-flex;
    top: calc(100% + .35rem + 38px + .35rem);
  }

  .gateway-edit-toggle svg {
    width: 18px;
    height: 18px;
  }

  .gateway-select-row.gateway-actions-open > .gateway-edit-toggle {
    color: var(--accent-color);
  }
  #agent-gateway-select {
    width: 100%;
    min-width: 0;
  }
  .gateway-manual-row {
    grid-column: 1 / -1;
    flex-wrap: wrap;
    width: 100%;
  }
  #gateway-manual-input {
    min-width: 0;
    flex-basis: 100%;
  }
  #gateway-manual-save,
  #gateway-manual-cancel {
    flex: 1 1 0;
    min-height: 38px;
  }
  .theme-selector-group {
    margin-left: 0;
    grid-column: span 1;
    min-width: 0;
    position: relative;
    width: 100%;
    height: 38px;
  }
  .theme-selector-group label {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 38px;
    border-radius: 9px;
    border: 1px solid var(--border-color);
    background: var(--input-bg-color);
    color: var(--secondary-text);
  }
  .theme-selector-group label svg {
    width: 18px;
    height: 18px;
  }
  #theme-selector {
    position: absolute;
    inset: 0;
    width: 100%;
    max-width: none;
    min-width: 0;
    opacity: 0;
    cursor: pointer;
  }
  #chat-box {
    min-height: 0;
    /* Side padding is subtracted before .message's percentage applies, so on a
       360px phone .65rem each way cost 21px before a bubble could claim any
       width at all. */
    padding: .9rem .5rem .75rem;
    gap: .45rem;
    background: linear-gradient(180deg, rgba(6,19,38,.86), rgba(8,20,42,.94) 34%, #0b1021 100%);
  }

  #history-sidebar,
  .history-header,
  #chat-history-list,
  .chat-container,
  .chat-header,
  #chat-box,
  .debug-panel,
  #message-form,
  #file-preview,
  .file-chip,
  .modal-content,
  .registry-modal-content,
  .registry-content,
  .advanced-options-content {
    background: linear-gradient(180deg, rgba(6,19,38,.96), rgba(8,20,42,.96) 48%, #0b1021 100%) !important;
  }

  #history-sidebar,
  .chat-container,
  .debug-panel,
  #message-form,
  .modal-content,
  .registry-modal-content {
    border-color: rgba(125,211,252,.18) !important;
  }

  .message.agent-message,
  .history-item,
  .registry-item,
  .agent-html-card,
  #file-preview,
  .file-chip {
    background: rgba(15,23,42,.72) !important;
    border-color: rgba(125,211,252,.18) !important;
  }

  #message-text,
  #agent-url-input,
  #agent-gateway-select,
  .form-group input,
  .form-group-small input,
  #registry-url-input,
  #registry-query-input,
  #num-results-input,
  #distance-threshold-input {
    background: rgba(15,23,42,.72) !important;
    border-color: rgba(125,211,252,.22) !important;
  }

  /* No per-bubble copy button on a phone. It cost 26px of every bubble plus
     the gutter behind it, on the screens with the least width to give, and it
     duplicates a control that already exists: #copy-selected-btn in the
     composer copies every checked message, reading the same
     .message-select-checkbox the bubbles still carry. One tap instead of one
     tap, and the multi-select case gets better rather than worse.

     The checkbox takes the vacated slot, so what is left in the corner is the
     thing that feeds the button that remains. */
  .message-copy-btn {
    display: none;
  }

  .message-select-checkbox {
    right: 8px;
  }

  .message-edit-btn {
    right: 32px;
  }

  /* Only the checkbox to clear now (8-24). */
  .message.copyable-message {
    padding-right: 32px;
  }

  /* Plus the edit button on the user's own messages (32-58). */
  .message.copyable-message.user-message {
    padding-right: 66px;
  }

  .message {
    /* 92% of the content box read as 87% of a 360px screen once the padding
       was taken out -- the percentage is not of the viewport. 96% of the
       narrowed box lands at about 92% of the screen on both a 360px Galaxy S21
       and a 440px iPhone, which is what "use the width" means on a phone. */
    max-width: 96%;
    font-size: .92rem;
    padding: 9px 12px;
  }

  /* .message.agent-message carries its own max-width: min(85%, 840px), and two
     classes outrank one no matter which media query the single-class rule sits
     in -- specificity is not affected by @media. Without this line the rule
     above moved the user's bubbles and left every agent reply at 85%, which on
     a 360px screen is 81% of it. Same specificity as the base rule, later in
     the file, so this wins. width:fit-content stays: a short reply should
     still be short, this only raises the ceiling for a long one. */
  .message.agent-message {
    max-width: 96%;
  }
  .message.rich-file-message,
  .message.agent-message.rich-file-message {
    width: 96%;
    max-width: 96%;
    align-self: center;
  }
  .message.status,
  .message.error {
    max-width: 96%;
    font-size: .78rem;
  }

  .pptx-card-header {
    align-items: stretch;
    flex-direction: column;
  }

  .pptx-card-title {
    white-space: normal;
  }

  .pptx-card-actions,
  .file-action-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(92px, 1fr));
    width: 100%;
  }

  .pptx-download-link,
  .file-download-link {
    min-height: 40px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    touch-action: manipulation;
  }
  .pptx-preview-stage {
    padding: 8px;
  }
  #message-form {
    /* No bottom inset, on either platform.

       The host app draws its own menu below this webview, so the system bar
       the inset describes -- home indicator on iOS, gesture bar on Android --
       sits below that menu, not below the page. Measured both ways: with
       viewport-fit=cover declared, iOS reports about 34 and a Galaxy S21
       reports 48, and honouring either one reopens a centimetre of dead space
       between the composer and the app's menu.

       The TOP inset is the opposite and is honoured in .chat-header: the
       webview really does begin at the physical top of the screen on both, so
       the notch and the status bar genuinely overlap the page. Same API, one
       end true and the other not, because of what the host app puts where. */
    padding: .5rem .55rem .5rem .55rem;
    gap: .5rem;
  }
  .composer-toolbar {
    gap: .4rem;
    overflow-x: auto;
    flex-wrap: nowrap;
    padding-bottom: 2px;
    scrollbar-width: none;
  }
  .composer-toolbar::-webkit-scrollbar {
    display: none;
  }
  #message-form .form-input-row {
    gap: .4rem;
    flex: 0 0 auto;
  }
  #message-text {
    min-height: 42px;
    height: 42px;
    max-height: 120px;
  }
  #message-text:placeholder-shown {
    height: 42px !important;
    max-height: 42px !important;
    overflow-y: hidden;
  }
  .icon-button {
    padding: 7px;
    min-width: 38px;
    min-height: 38px;
  }
  .icon-button svg {
    width: 18px;
    height: 18px;
  }
}

@media (max-width: 420px) {
  .controls-wrapper > .icon-button,
  .controls-wrapper > a.icon-button {
    min-width: 36px;
    min-height: 36px;
  }
  .agent-url-group label {
    width: auto;
  }
  #theme-selector {
    width: 100%;
    padding-left: 7px;
    padding-right: 7px;
  }
  #file-list {
    min-width: 0;
    width: 100%;
  }
  #file-preview {
    width: 100%;
    max-width: none;
  }
}

@media (min-width: 769px) and (max-width: 1100px) {
  body {
    padding: 8px;
  }

  .app-shell {
    gap: 8px;
    min-height: 620px;
  }

  #history-sidebar {
    width: clamp(196px, 24vw, 230px);
    min-width: 196px;
  }

  .chat-header {
    padding: .7rem .85rem;
  }

  .chat-header h1 {
    display: none;
  }

  .controls-wrapper {
    gap: .4rem;
    grid-template-columns: repeat(6, 40px) minmax(0, 1fr) minmax(0, 128px);
  }

  .agent-url-group label {
    display: block;
  }

  #agent-url-input {
    width: 100%;
  }

  #message-form {
    padding: .75rem .85rem;
  }

  #chat-box {
    padding: 1rem;
  }
}

.docker-section { margin: 1rem 2rem 2rem; padding-top: 1rem; overflow-y: auto; }
.section-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 1rem; }
.section-header h2 { margin: 0; font-size: 1.1rem; color: var(--text-primary); }
.docker-form .form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; padding: 1rem; margin: 1rem; }
.docker-form fieldset { border: 1px solid var(--border-color); border-radius: 8px; padding: 1rem; margin: 1rem; }
.docker-form legend { padding: 0 .5rem; color: var(--text-secondary); }
.docker-form button { margin: 0 1rem 1rem; }

.docker-list table { width: 100%; border-collapse: collapse; margin-top: 1rem; }
.docker-list th, .docker-list td { padding: .6rem; text-align: left; border-bottom: 1px solid var(--border-color); word-break: break-all; }
.docker-list th { font-weight: 600; color: var(--text-secondary); }
.docker-list td { font-family: 'Poppins', monospace; font-size: .9rem; }
.docker-list td:first-child { font-family: monospace; }

.port-input {
  background: var(--input-bg-color);
  border: 1px solid var(--input-border-color);
  color: var(--primary-text);
  border-radius: 6px;
  padding: 6px 6px;
  font-size: .7rem;
  margin: 4px 12px;
  transition: border-color .3s ease, box-shadow .3s ease;
}

.action-button {
  background: var(--accent-color);
  color: #fff;
  border: none;
  padding: 10px 16px;
  border-radius: 8px;
  cursor: pointer;
  font-weight: 600;
  font-size: .9rem;
  transition: all .2s ease;
}
.action-button:hover {
  filter: brightness(1.1);
}
.action-button:active {
  transform: scale(0.98);
}
.action-button:disabled {
  background: var(--border-color);
  color: var(--secondary-text);
  cursor: not-allowed;
  opacity: 0.6;
}
.stop-btn {
  background: var(--error-color);
}
.stop-btn:hover {
  filter: brightness(1.1);
}
.add-btn {
  background: transparent;
  border: 1px solid var(--accent-color);
  color: var(--accent-color);
  margin-top: .5rem;
}
.add-btn:hover {
  background: var(--accent-color);
  color: #fff;
}

.dynamic-input-group { display: flex; align-items: center; gap: .5rem; margin-bottom: .1rem; }
.dynamic-input-group input { flex: 1; }

.remove-btn {
  background: var(--button-bg); border: 1px solid var(--border-color); color: var(--text-secondary);
  width: 16px; height: 16px; border-radius: 50%; cursor: pointer; font-size: 0.8rem; line-height: 1; padding: 0;
}
.remove-btn:hover { background: #e53935; color: #fff; border-color: #e53935; }

.description-btn {
  background: var(--button-bg); border: 1px solid var(--border-color); color: var(--text-secondary);
  width: 16px; height: 16px; border-radius: 50%; cursor: pointer; font-size: 0.8rem; line-height: 1; padding: 0;
}

.loading-message, .error-message { text-align: center; padding: 1.2rem; color: var(--text-secondary); }
.error-message { color: #e53935; background: rgba(229,57,53,.1); border-radius: 8px; }

.nav-link {
  display: flex; align-items: center; gap: .5rem; text-decoration: none;
  color: var(--text-secondary); font-weight: 500; padding: 6px 10px; border-radius: 8px; transition: background-color .2s;
}
.nav-link:hover { background: var(--button-bg); color: var(--text-primary); }
.nav-link-header { color: var(--icon-color); padding: 8px; border-radius: 50%; display: flex; align-items: center; justify-content: center; }
.nav-link-header:hover { background: var(--button-bg-hover); }


.planner-message {
  max-width: min(920px, 96%);
}

.planner-approval-card,
.planner-result-card {
  display: grid;
  gap: 12px;
  padding: 14px;
  border: 1px solid var(--border-color);
  border-radius: 8px;
  background: var(--surface-color, rgba(255,255,255,.04));
}

.planner-card-title {
  font-weight: 700;
  color: var(--text-primary);
}

.planner-card-plan {
  color: var(--text-secondary);
  font-size: .92rem;
  line-height: 1.45;
}

.planner-step-choice {
  display: grid;
  gap: 6px;
}

.planner-step-choice label {
  font-size: .85rem;
  color: var(--text-secondary);
}

.planner-step-choice select {
  width: 100%;
  min-height: 38px;
  border: 1px solid var(--input-border-color);
  border-radius: 8px;
  background: var(--input-bg-color);
  color: var(--primary-text);
  padding: 8px 10px;
}
.planner-step-choice .csel { width: 100%; }
.planner-step-choice .csel-trigger { min-height: 38px; }

.planner-approval-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
}

.planner-run-btn {
  border: none;
  border-radius: 8px;
  background: var(--accent-color);
  color: #fff;
  cursor: pointer;
  font-weight: 700;
  padding: 9px 14px;
}

.planner-run-btn:disabled {
  cursor: not-allowed;
  opacity: .65;
}

.planner-result-failed {
  border-color: var(--error-color, #e53935);
}

.planner-final-card {
  border-color: var(--accent-color);
}

@media (max-width: 640px) {
  .planner-message {
    max-width: 100%;
  }
  .planner-approval-card,
  .planner-result-card {
    padding: 12px;
  }
}


.planner-artifact-list {
  display: grid;
  gap: 10px;
}

.planner-artifact-item {
  display: grid;
  gap: 8px;
}

/* Non-fetchable file/link (e.g. a sandbox: reference the agent didn't resolve). */
.planner-artifact-item.unsupported-file {
  display: block;
  padding: 8px 10px;
  border: 1px dashed var(--border-color);
  border-radius: 8px;
  color: var(--secondary-text);
  font-size: .85rem;
}
.unsupported-link {
  color: var(--secondary-text);
  text-decoration: line-through;
}
.unsupported-link-badge {
  text-decoration: none;
  font-size: .8em;
  white-space: nowrap;
  opacity: .85;
}

.planner-artifact-item img,
.planner-artifact-item video {
  max-width: 100%;
  border-radius: 8px;
  border: 1px solid var(--border-color);
}

.planner-artifact-item audio {
  width: 100%;
}

html.embedded-webview,
html.embedded-webview body {
  height: 100%;
  min-height: 0;
  overflow: hidden;
}

html.embedded-webview body {
  padding: 0;
}

/* Z-UP's embedded pane renders rem-based text ~36% larger than the native
   sidebar (Ctrl+- has no effect there -- the host app doesn't wire up
   webview zoom), so scale the root font-size down to match. Applied
   unconditionally: the html.embedded-webview class depends on a ?embedded=1
   URL param that Z-UP does not appear to actually pass. */
html {
  font-size: 89%;
}

/* Match the app's surfaces to Z-UP's native sidebar color (#1F213E, indigo)
   instead of the default midnight theme's neutral gray. --surface-color is
   pinned to the exact sidebar color since it's the dominant visible
   background; the others are lighter/darker tints of the same hue. */
body[data-theme="midnight"] {
  --bg-color: #171930;
  --surface-color: #1f213e;
  --agent-bubble: #262a4c;
  --border-color: #34385f;
}

html.embedded-webview .app-shell {
  height: 100%;
  min-height: 0;
  max-height: 100%;
}

html.embedded-webview .chat-main,
html.embedded-webview .chat-container {
  height: 100%;
  min-height: 0;
}

html.embedded-webview #chat-box {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
}

html.embedded-webview #message-form {
  flex: 0 0 auto;
  position: static;
}

html.embedded-webview #history-sidebar {
  height: 100%;
}

@media (min-width: 769px) {
  body {
    padding: 0;
  }

  .app-shell {
    height: 100vh;
    height: 100dvh;
  }
}

/* ---- Company & sharing modal ---- */
/* .modal-content:not(.registry-modal-content) centre-aligns text; this panel is
   a form and a list, so it opts back out. */
.company-modal-content {
  text-align: left;
  width: min(560px, 92vw);
  max-height: 84vh;
}

.company-content {
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
  overflow-y: auto;
}

.company-section h3 {
  margin: 0 0 .5rem;
  font-size: .95rem;
  color: var(--primary-text);
}

.company-hint {
  margin: .35rem 0 .75rem;
  font-size: .8rem;
  line-height: 1.45;
  color: var(--secondary-text);
}

.company-identity {
  display: flex;
  align-items: center;
  gap: .5rem;
  flex-wrap: wrap;
}

.company-identity code,
.company-new-code code {
  flex: 1 1 auto;
  min-width: 0;
  padding: .5rem .6rem;
  border-radius: 8px;
  background: var(--input-bg-color);
  border: 1px solid var(--input-border-color);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .8rem;
  /* These are long opaque strings; wrap rather than overflow the dialog. */
  overflow-wrap: anywhere;
}

.company-id-label {
  flex: 0 0 4.5rem;
  color: var(--secondary-text);
  font-size: .8rem;
}

.company-new-code {
  display: flex;
  align-items: center;
  gap: .5rem;
  flex-wrap: wrap;
  margin-top: .75rem;
}

.company-new-code .company-hint {
  flex-basis: 100%;
  margin: 0;
}

.company-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: .4rem;
}

.company-list-item {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .5rem .6rem;
  border-radius: 8px;
  border: 1px solid var(--border-color);
  background: var(--agent-bubble);
  font-size: .85rem;
}

.company-list-item code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .8rem;
  overflow-wrap: anywhere;
}

.company-list-empty {
  color: var(--secondary-text);
  justify-content: center;
}

.company-tags {
  display: flex;
  gap: .3rem;
  margin-right: auto;
}

.company-tag {
  padding: .1rem .4rem;
  border-radius: 999px;
  font-size: .7rem;
  text-transform: uppercase;
  letter-spacing: .04em;
  background: var(--modal-button-secondary-bg);
  color: var(--modal-button-secondary-text);
}

.company-row-action {
  padding: .25rem .6rem;
  font-size: .75rem;
}

.company-tag-remove {
  border: none;
  background: transparent;
  color: inherit;
  cursor: pointer;
  font-size: .85rem;
  line-height: 1;
  padding: 0 0 0 .1rem;
  opacity: .75;
}
.company-tag-remove:hover { opacity: 1; }

.company-join-row {
  display: flex;
  gap: .5rem;
  flex-wrap: wrap;
}

.company-join-row input {
  flex: 1 1 220px;
  min-width: 0;
  padding: .5rem .6rem;
  border-radius: 8px;
  background: var(--input-bg-color);
  border: 1px solid var(--input-border-color);
  color: var(--primary-text);
  font-size: .85rem;
}

.company-leave-btn {
  margin-top: .75rem;
}

/* ---- Relay routes modal ---- */
.routes-form {
  display: flex;
  flex-direction: column;
  gap: .5rem;
}
.routes-form input {
  padding: .5rem .6rem;
  border-radius: 8px;
  background: var(--input-bg-color);
  border: 1px solid var(--input-border-color);
  color: var(--primary-text);
  font-size: .85rem;
}
/* Route rows stack the info and its actions on separate lines (many buttons
   otherwise crowd the info off the row). */
.company-list-item.route-row {
  flex-direction: column;
  align-items: stretch;
}
.route-actions {
  display: flex;
  flex-wrap: wrap;
  gap: .4rem;
}
.route-info {
  display: flex;
  flex-direction: column;
  gap: .25rem;
  margin-right: auto;
  min-width: 0;
}
.route-info > div:first-child {
  display: flex;
  align-items: center;
  gap: .4rem;
  flex-wrap: wrap;
}
.route-target {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .75rem;
  color: var(--secondary-text);
  overflow-wrap: anywhere;
}


/* When the owner-only Relay Routes icon is present, the desktop nav needs a 6th
   icon column. Scoped to desktop so the mobile layout (which hides these icons
   and uses the hamburger) is never affected. Default stays the 5-icon grid. */
@media (min-width: 769px) {
  .controls-wrapper.routes-visible {
    grid-template-columns: repeat(7, 42px) minmax(0, 1fr) minmax(0, 150px);
  }
  .controls-wrapper.routes-visible .theme-selector-group {
    grid-column: 7;
  }
}

/* ---- A2A send-mode toggle in the composer ---- */
.a2a-toggle {
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  padding: 0 .5rem;
  height: 38px;
  min-width: 38px;
  border-radius: 9px;
  border: 1px solid var(--border-color);
  background: var(--input-bg-color);
  color: var(--secondary-text);
  font-size: .78rem;
  font-weight: 600;
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
}
.a2a-toggle input { accent-color: var(--accent-color); cursor: pointer; margin: 0; }
/* Lit-up state when A2A mode is on. */
.a2a-toggle:has(input:checked) {
  border-color: var(--accent-color);
  color: var(--accent-color);
  background: color-mix(in srgb, var(--accent-color) 14%, var(--input-bg-color));
}

/* ---- Invite-as-external toggle in the company modal ---- */
.company-invite-external {
  display: flex;
  align-items: center;
  gap: .4rem;
  font-size: .82rem;
  color: var(--secondary-text);
  margin: .25rem 0 .6rem;
  cursor: pointer;
  user-select: none;
}
.company-invite-external input { accent-color: var(--accent-color); cursor: pointer; margin: 0; }

/* A2A identity block in the Start Container dialog. The client id is derived
   (a2a-agent-<owner>-<key>) so it can be previewed; the secret only appears
   after an explicit reveal and is cleared when the dialog closes. */
.a2a-identity-line { margin: 6px 0 2px; font-size: .88rem; }
.a2a-identity-line code { font-size: .85em; word-break: break-all; }
.a2a-identity-note { display: block; opacity: .7; font-size: .82rem; margin: 2px 0 6px; }
.a2a-identity-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 6px; }
.a2a-env-out {
  width: 100%;
  font-family: var(--mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: .8rem;
  resize: vertical;
}

/* Live progress of a container launch job in the Start Container dialog. */
.start-container-status { margin: 8px 0 0; font-size: .88rem; opacity: .85; }


/* The gateway row's phone-only pieces, kept out of the desktop layout.
   The icon replaces a caption that fits perfectly well here, and the toggle
   folds away a + and a - that have room to stay put -- leaving it visible
   added a third button that does nothing the other two do not. Both live in
   the markup unconditionally, so they are hidden here rather than rendered
   conditionally. */
@media (min-width: 769px) {
  .gateway-label-icon,
  .gateway-edit-toggle {
    display: none;
  }
}

/* ── Mobile type scale ──────────────────────────────────────────────────────
   Two sizes, not seven. Measured on the phone, the chat screen was running
   .76rem, .78rem, .8rem, .85rem, .86rem, .92rem and a flat 16px at once --
   10.8px to 16px, a 48% spread, with the composer the only thing in absolute
   pixels and therefore the only thing that ignores the 89% root scale.

   CONTENT is what the person reads and writes: a bubble and the box that
   feeds it hold the same words a second apart, so they are the same size.
   CHROME is the configuration above them, legitimately a step down.

   The composer's 16px was the iOS trick that stops a focused input zooming
   the page. The rule that set it says in its own comment that this document
   disables zoom (user-scalable=no) and does not need it.

   Change CONTENT here if the text should be bigger; the two-tier shape does
   not depend on the numbers. */
@media (max-width: 768px) {
  /* CONTENT — 0.92rem ≈ 13.1px */
  #message-text,
  .message {
    font-size: .92rem;
  }

  /* CHROME — 0.85rem ≈ 12.1px */
  #agent-url-input,
  #agent-route-select,
  #agent-gateway-select,
  #gateway-manual-input,
  .agent-url-group label,
  .message.status,
  .message.error,
  .nav-menu-item {
    font-size: .85rem;
  }

  /* .agent-url-input-row > #agent-url-input is (1,1,0) and pins .8rem; an ID
     alone is (1,0,0) and loses to it no matter how late it appears. Measured
     on the device: this field rendered 11.39px while every other control in
     the tier rendered 12.10px. */
  .agent-url-input-row > #agent-url-input {
    font-size: .85rem;
  }

  /* The picker was pinned with !important by the no-zoom rule, so matching
     specificity is not enough to move it. */
  #agent-gateway-select,
  #message-text {
    font-size: unset;
  }
  #agent-gateway-select {
    font-size: .85rem !important;
  }
  #message-text {
    font-size: .92rem !important;
  }
}

/* Video full screen inside the desktop app (no element full screen there):
   the wrapper, moved under <body>, covers the window. */
.video-wrap.video-fake-fullscreen {
  position: fixed;
  inset: 0;
  width: 100vw;
  height: 100vh;
  max-width: none;
  margin: 0;
  z-index: 3000;
  background: #000;
  display: flex;
  align-items: center;
  justify-content: center;
}
.video-wrap.video-fake-fullscreen video {
  width: 100% !important;
  height: 100% !important;
  max-width: none !important;
  max-height: none !important;
  object-fit: contain;
  border-radius: 0 !important;
  box-shadow: none !important;
}
.video-wrap.video-fake-fullscreen .video-fullscreen-btn { display: none; }
.video-fake-fullscreen-close { display: none; }
.video-wrap.video-fake-fullscreen .video-fake-fullscreen-close {
  position: fixed;
  top: 16px;
  right: 16px;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: rgba(255, 255, 255, .14);
  border: none;
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 3001;
  cursor: pointer;
}
.video-fake-fullscreen-close svg { width: 22px; height: 22px; }

/* Chat messages never shrink: #chat-box is a flex column, and a shrunken
   message (e.g. an image laid out before it loaded) let its Save link spill
   under the next message. The chat scrolls instead. */
#chat-box > * { flex-shrink: 0; }

/* A stored file while its link is being fetched. */
.message.object-loading { opacity: .7; font-size: .9rem; padding: 10px 14px; }

/* Storage usage line in the menu (not clickable) and the gateway panel's storage status. */
.nav-menu-item.nav-menu-storage {
  cursor: default;
  font-size: .78rem;
  color: var(--secondary-text, #888);
  border-top: 1px solid var(--border-color, rgba(127, 127, 127, .25));
  border-radius: 0;
}
.nav-menu-item.nav-menu-storage[data-level="warning"],
.gateway-storage-status[data-level="warning"] { color: #b7791f; }
.nav-menu-item.nav-menu-storage[data-level="critical"],
.gateway-storage-status[data-level="critical"] { color: #c53030; font-weight: 600; }

/* Notification channel form (stacked like the route form). */
.notify-form { margin-top: 8px; }
.notify-form input[hidden] { display: none; }
.agent-notify { margin-top: 14px; }
.agent-notify h4 { margin: 10px 0 4px; font-size: .9rem; }
.agent-notify-token { display: block; word-break: break-all; font-size: .78rem; }
.agent-notify-token:empty { display: none; }

/* Invite lists: group headings and member-status tags. */
.company-list-heading { list-style: none; margin: 10px 0 2px; font-size: .8rem; font-weight: 600; opacity: .8; }
.company-tags .company-tag[data-level="ok"] { color: #2f855a; }
.company-tags .company-tag[data-level="muted"] { opacity: .65; }
.company-new-code-kind { font-weight: 600; margin-bottom: 4px; }

/* Off-site chat backup (gateway settings): one labelled field per line. */
.offsite-form { margin-top: 8px; }
.offsite-field {
  display: flex;
  flex-direction: column;
  gap: .25rem;
  font-size: .8rem;
  color: var(--secondary-text, var(--primary-text));
}
.offsite-field input { width: 100%; box-sizing: border-box; }
.offsite-field small { margin: 0; }
.offsite-actions { display: flex; flex-wrap: wrap; gap: .5rem; }

/* ---- Light theme ------------------------------------------------------------
   The page was designed dark: the body gradient and, on phones, the chat area,
   header, composer, agent bubbles and inputs are painted dark navy with
   !important, whatever the theme. The light theme only swaps the variables, so
   on a phone it put dark text on that navy (agent replies unreadable), and the
   nav menu was a dark panel with dark items on every screen size. This block
   gives the light theme its own surfaces; the dark themes are untouched. */
html:has(body[data-theme="light"]) { background-color: var(--bg-color, #f5f5f5); }

body[data-theme="light"] {
  --link-color: #3b1fc4;
  background: #eef0f3;
}

body[data-theme="light"] .nav-menu-button {
  background: var(--surface-color);
  border-color: var(--border-color);
  color: var(--secondary-text);
}

body[data-theme="light"] .nav-menu-panel {
  background: var(--surface-color);
  border-color: var(--border-color);
  box-shadow: 0 12px 28px rgba(0,0,0,.14);
}

body[data-theme="light"] .nav-menu-item:hover {
  background: rgba(0,0,0,.05);
}

body[data-theme="light"] .message pre,
body[data-theme="light"] .message code {
  background: rgba(0,0,0,.06);
  border-color: rgba(0,0,0,.08);
  box-shadow: none;
}
body[data-theme="light"] .message pre code {
  background: transparent;
}

@media (max-width: 768px) {
  body[data-theme="light"],
  body[data-theme="light"] .app-shell,
  body[data-theme="light"] .chat-main {
    background: var(--bg-color);
  }

  body[data-theme="light"] #history-sidebar,
  body[data-theme="light"] .history-header,
  body[data-theme="light"] #chat-history-list,
  body[data-theme="light"] .chat-container,
  body[data-theme="light"] .chat-header,
  body[data-theme="light"] #chat-box,
  body[data-theme="light"] .debug-panel,
  body[data-theme="light"] #message-form,
  body[data-theme="light"] #file-preview,
  body[data-theme="light"] .modal-content,
  body[data-theme="light"] .registry-modal-content,
  body[data-theme="light"] .registry-content,
  body[data-theme="light"] .advanced-options-content {
    background: var(--surface-color) !important;
    border-color: var(--border-color) !important;
  }

  body[data-theme="light"] #chat-box {
    background: var(--bg-color) !important;
  }

  body[data-theme="light"] .chat-header {
    border-bottom-color: var(--border-color);
  }
  body[data-theme="light"] .chat-header::before {
    display: none;
  }

  body[data-theme="light"] .message.agent-message,
  body[data-theme="light"] .history-item,
  body[data-theme="light"] .registry-item,
  body[data-theme="light"] .agent-html-card,
  body[data-theme="light"] .file-chip {
    background: var(--agent-bubble) !important;
    border-color: var(--border-color) !important;
  }

  body[data-theme="light"] #message-text,
  body[data-theme="light"] #agent-url-input,
  body[data-theme="light"] #agent-gateway-select,
  body[data-theme="light"] .form-group input,
  body[data-theme="light"] .form-group-small input,
  body[data-theme="light"] #registry-url-input,
  body[data-theme="light"] #registry-query-input,
  body[data-theme="light"] #num-results-input,
  body[data-theme="light"] #distance-threshold-input {
    background: var(--input-bg-color) !important;
    border-color: var(--input-border-color) !important;
    color: var(--primary-text);
  }

  body[data-theme="light"] #history-toggle-bottom-btn,
  body[data-theme="light"] .theme-selector-group label {
    background: var(--surface-color);
    border-color: var(--border-color);
    color: var(--secondary-text);
  }
}

/* An agent-made web page or game, played in a sandboxed frame (buildHtmlPlayer). */
.html-player-stage:empty { display: none; }
.html-player-frame {
  display: block;
  width: 100%;
  height: min(70vh, 560px);
  border: 0;
  background: #fff;
}
.html-player-card.html-player-full {
  position: fixed;
  inset: 0;
  z-index: 3000;
  border-radius: 0;
  display: flex;
  flex-direction: column;
}
.html-player-card.html-player-full .html-player-stage { flex: 1; min-height: 0; }
.html-player-card.html-player-full .html-player-frame { height: 100%; }

/* A file the user uploaded, shown on their side of the chat. */
.message.user-file,
.agent-image.user-file {
  align-self: flex-end;
}

/* Multi-person invite codes: options and the people who joined with a code. */
.company-invite-options {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 18px;
  margin: 8px 0 10px;
  font-size: 0.9em;
}
.company-invite-options label { display: flex; align-items: center; gap: 8px; }
.company-list-item.company-list-sub {
  padding-left: 22px;
  font-size: 0.9em;
  opacity: 0.9;
}

/* While the agent works and nothing is typed, the send button is Stop. */
#send-button.is-stop,
#send-button.is-stop:hover {
  background: #d9534f;
  border-color: #d9534f;
  color: #fff;
}

/* "Use my location" (location.js): no animation, the app's webview blinks on them */
#location-button.is-on { color: #3ccf91; }
#location-toast { position: fixed; left: 50%; bottom: 96px; transform: translateX(-50%); z-index: 9000;
  max-width: min(92vw, 520px); background: #1b2747; color: #e6ebf5; border: 1px solid #2b3a62;
  border-radius: 10px; padding: 10px 14px; font-size: 14px; line-height: 1.4; box-shadow: 0 6px 24px rgba(0,0,0,.35); }
#location-toast[hidden] { display: none; }
