/* ─── CSS Variables ─────────────────────────────────────────────────────────── */

:root {
  /* Default: dark theme (GitHub Dark-ish). Override via :root.light for light mode. */
  --bg-base:        #0d1117;
  --bg-surface:     #161b22;
  --bg-elevated:    #21262d;
  --bg-card:        #1c2128;
  --bg-hover:       #2d333b;
  --border:         #30363d;
  /* Border color reserved for glass-style capsules (conv-list-toggle,
     core pickers, search pill, wiki rail toggles, chips). Sits a notch
     lighter than --border in dark mode so the rim reads as "raised" even
     when --glass-glare-brightness is dialed low. Applied via the
     :root[data-style~="glass"] rule near the glass glare block. */
  --border-glass:   #4a5565;
  --text-primary:   #e6edf3;
  --text-secondary: #8b949e;
  /* In dark mode --text-muted aliases --text-secondary on purpose; the
     original #484f58 read as too dim against the dark surface. Light
     variants below keep their distinct muted shade. */
  --text-muted:     #8b949e;
  /* Accent blue is derived: --accent-blue-base is the raw hex (settable by
     the Accent color picker; dark/light mode each override below) and
     --accent-blue-sat-mult is a 0–1 multiplier driven by the "Blue
     saturation" slider in the Settings → Colors group. The derived
     --accent-blue value cascades to every consumer (.btn-primary, focus
     rings, sidebar accents, the iMessage-style Me bubble, etc.) so a
     single slider re-saturates the whole accent across the app. */
  --accent-blue-base: #1c95ff;
  --accent-blue-sat-mult: 1.0;
  --accent-blue: hsl(from var(--accent-blue-base) h calc(s * var(--accent-blue-sat-mult)) l);
  --accent-green:   #3fb950;
  --accent-orange:  #d29922;
  --accent-red:     #f85149;
  --accent-purple:  #bc8cff;
  --font-mono:      'JetBrains Mono', 'Fira Code', 'Cascadia Code', monospace;
  --font-ui:        -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
  --fw-regular:     390;
  --fw-medium:      490;
  --fw-semibold:    590;
  --fw-bold:        690;
  /* Vertical-padding offset applied to nav rows (sidebar + facets nav).
     Driven by the dev GUI spacing slider. */
  --nav-spacing-offset: -1px;
  /* Conversation list font scale — separate desktop and mobile so the dev GUI
     can tune each independently. Inner rows use em so they multiply against
     this baseline. */
  --conv-list-scale-desktop: 1.12;
  --conv-list-scale-mobile:  1;
  --sidebar-width:  220px;
  --top-bar-height: 56px;
  /* Radius baseline doubled (formerly sm=8/md=12/lg=20/btn=10). The
     dev-GUI "Corner radius" slider scales these; 1.00× is the new
     default. Anyone with a stored hp:radius-scale from before the bump
     gets it halved once via the migration in index.html's pre-paint
     loader so the rendered look is preserved. */
  --radius-sm:      16px;
  --radius-md:      24px;
  --radius-lg:      40px;
  --radius-pill:    100px;
  --radius-btn:     20px;
  --transition:     150ms ease;
  /* ── Page-header tokens ─────────────────────────────────────────────────
     Single source of truth for the chrome at the top of every primary view
     (Conversations, Discover, Account, Help, and the wiki sub-modes Chat /
     Identity / Edit / Wiki/Sources). Edit these to retune all page headers
     in one place. The .page-header CSS class below references them. */
  --page-header-padding-y:    12px;
  --page-header-padding-x:    24px;
  --page-header-title-size:   1.1rem;
  /* Two height knobs:
       --page-header-height       — wiki center-panel inner headers
                                    (Identity / Chat / Wiki sub-views).
                                    Defaults to 56px so they stay flush
                                    with the wiki sidebar's New Facet wrap
                                    and the global top bar.
       --nav-page-header-height   — the 5 main-nav pages (Discover, Facets,
                                    Conversations, Account, Help). Tunable
                                    via the dev GUI slider so the chrome
                                    can be made shorter than the wiki rail. */
  --page-header-height:      56px;
  --nav-page-header-height:  40px;
  --page-header-mobile-height: 44px;
  /* Floor the page-header content row at the height of the Conversations
     search input (28px). Title-only views (Discover/Account/Help/etc.) get
     the extra space as balanced vertical padding (align-items:center) so
     every page header outer-renders at the same total height. */
  --page-header-content-min-height: 28px;
  /* ── Input-height token ─────────────────────────────────────────────────
     Single height for ALL typed-input affordances (text inputs, textareas,
     search bars, chat composers). 38px matches the chat-composer textarea
     min-height already used across conversations.js + wiki.js, and aligns
     with the Send button's padding (8px × 2 + ~22px content). Multiline
     fields use this as min-height and grow from there. The mobile rule
     (~line 1715) deliberately overrides to 44px for touch targets. */
  --input-height: 38px;

  /* Selected-facet border opacity multiplier. Range 0–200, default 40.
     Applied to the border color of an active facet row via color-mix:
       border-mix-percent = clamp(0%, intensity * 0.5%, 100%)
     so 0 → invisible border, 40 → 20% opacity (calibrated baseline —
     subtle rim that reads as selection without dominating), 100 → 50%
     opacity, 200 → 100% fully opaque. Width stays fixed at 1px — the
     slider only controls how "lit" the rim color reads. Decoupled from
     --facet-selected-bg-intensity so border and bg are dialed
     independently. See cloudflare/pages/components/wiki.js buildSubRow
     for the consumer. */
  --facet-selected-border-intensity: 40;

  /* Selected-facet background-tint intensity. Range 0–200, default 100.
     Multiplies the background color-mix percent applied to active rail
     rows: bg-mix-percent = clamp(0, intensity * 0.18%, 36%). 0 → fully
     transparent, 100 → 18% tint (baseline), 200 → 36% tint. Decoupled
     from --facet-selected-border-intensity so the user can dial border
     and bg independently. */
  --facet-selected-bg-intensity: 100;

  /* Glass-style edge-glare brightness multiplier. Range 0–200, default 30.
     Scales the ::after layer's opacity (the existing 0.9 in dark / 0.35 in
     light) by intensity/100, so 0 = invisible glare, 30 = the calibrated
     default (subtle rim), 100 = the unscaled base, 200 = doubled. Only
     takes effect under :root[data-style~="glass"] because that's the only
     place the ::after layer exists. See the "Glass — specular edge glare"
     block below for the consumer rules. */
  --glass-glare-brightness: 30;

  /* Incoming message-bubble border intensity. Range 0–200, default 100.
     Opacity multiplier (intensity * 1%) on the calibrated baseline color
       color-mix(in srgb, var(--accent-blue) 10%, var(--border))
     applied to all 4 edges of the 1px outline around incoming
     .conv-excerpt-bubble cells under the Liquid/Glass surface styles:
       0   → fully transparent border (top, bottom, left, right all gone)
       100 → 100% opaque baseline (matches the prior hardcode look)
       200 → clamped at 100% by the browser (no-op above 100, kept in the
             range for slider parity with the other intensity controls)
     Outgoing "Me" bubbles are unaffected (they're solid var(--accent-blue)).
     No effect under the Flat surface style — the inline identity-color
     left bar set by conversations.js is a separate attribute. */
  --incoming-bubble-border-intensity: 20;
}

:root.light {
  /* "Crisp" — default light variant. Near-black text, readable muted. */
  --bg-base:        #ffffff;
  --bg-surface:     #f5f7fa;
  --bg-elevated:    #ebeef3;
  --bg-card:        #ffffff;
  --bg-hover:       #e1e6ed;
  --border:         #b8bec8;
  --border-glass:   #a8b0c0;
  --text-primary:   #000000;
  --text-secondary: #1a2236;
  --text-muted:     #3a4255;
  --accent-blue-base: #1c95ff;
  --accent-green:   #15692e;
  --accent-orange:  #7d5400;
  --accent-red:     #b0151f;
  --accent-purple:  #6c3fc7;
}

/* Settings popover shell — anchored to the palette button. The .settings-popover
   modifier extends this base for the disclosure-grouped layout. */
.theme-variant-popover {
  position: absolute;
  top: calc(var(--top-bar-height) + 4px);
  right: 12px;
  z-index: 1000;
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 6px;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: 0 6px 20px rgba(0,0,0,0.18);
  min-width: 200px;
}
.theme-variant-popover.hidden { display: none; }

/* Dev GUI popover — font + accent customization. Reuses .theme-variant-popover
   shell for positioning; controls below get their own styling. */
.dev-gui-section {
  padding: 8px 10px;
}
.dev-gui-section + .dev-gui-section {
  border-top: 1px solid var(--border);
}
.dev-gui-label {
  display: block;
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-secondary);
  margin-bottom: 6px;
  font-family: var(--font-ui);
}
.dev-gui-select {
  width: 100%;
  padding: 6px 8px;
  font-size: 0.82rem;
  background: var(--bg-base);
  color: var(--text-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-family: var(--font-ui);
  cursor: pointer;
}
.dev-gui-select:focus {
  outline: none;
  border-color: var(--accent-blue);
}
.dev-gui-color-row {
  display: flex;
  gap: 8px;
  align-items: center;
}
.dev-gui-color {
  width: 36px;
  height: 30px;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: transparent;
  cursor: pointer;
  flex-shrink: 0;
}
.dev-gui-range {
  width: 100%;
  cursor: pointer;
  accent-color: var(--accent-blue);
}
.dev-gui-reset {
  width: 100%;
  padding: 6px 10px;
  font-size: 0.78rem;
  background: var(--bg-base);
  color: var(--text-secondary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-family: var(--font-ui);
  transition: background 120ms, color 120ms, border-color 120ms;
}
.dev-gui-reset:hover {
  background: var(--bg-hover);
  color: var(--text-primary);
  border-color: var(--accent-blue);
}

/* Settings popover — disclosure-grouped layout with inner scroll wrapper.
   Overrides the parent .theme-variant-popover gap/padding so the scroll
   container + footer can sit edge-to-edge inside the popover shell. */
.settings-popover {
  gap: 0;
  padding: 0;
  overflow: hidden;
}
.settings-popover-scroll {
  max-height: min(82vh, 680px);
  overflow-y: auto;
  overscroll-behavior: contain;
}
.settings-popover-footer {
  border-top: 1px solid var(--border);
  padding: 10px 12px;
  display: flex;
  gap: 8px;
  flex-shrink: 0;
}
.settings-popover-footer .dev-gui-reset {
  margin: 0;
  flex: 1;
}
.settings-group {
  border-bottom: 1px solid var(--border);
}
.settings-group:last-child { border-bottom: none; }
.settings-group-summary {
  list-style: none;
  cursor: pointer;
  padding: 10px 12px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 0.78rem;
  font-weight: var(--fw-semibold);
  color: var(--text-primary);
  font-family: var(--font-ui);
  letter-spacing: 0.02em;
  text-transform: uppercase;
}
.settings-group-summary::-webkit-details-marker { display: none; }
.settings-group-summary:hover { background: var(--bg-hover); }
.settings-group-body {
  padding: 4px 0 8px;
}
.settings-group-chev {
  display: inline-block;
  font-size: 0.7rem;
  color: var(--text-muted);
  transition: transform 150ms;
  transform: rotate(180deg);
}
.settings-group[open] .settings-group-chev {
  transform: rotate(0deg);
}

/* ─── Reset & Base ───────────────────────────────────────────────────────────── */

*, *::before, *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html {
  font-size: 15px;
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}
html, body {
  height: 100%;
  overflow: hidden;
  background: var(--bg-base);
  color: var(--text-primary);
  font-family: var(--font-ui);
  font-weight: var(--fw-medium);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  /* Allow children to opt into safe-area insets via env(...) without
     re-declaring this on every block. */
}

/* On mobile, switch the root height from 100% (which resolves against the
   layout viewport including iOS Safari URL bar) to dynamic viewport height
   so the actual visible area is what we lay out against. dvh isn't
   universally supported on older browsers — they fall back to the 100%
   above. */
@supports (height: 100dvh) {
  html, body { height: 100dvh; }
}
body {
  font-size: 13px;
}

a {
  color: var(--accent-blue);
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
}

/* ─── Scrollbars ─────────────────────────────────────────────────────────────── */

::-webkit-scrollbar {
  width: 6px;
  height: 6px;
}

::-webkit-scrollbar-track {
  background: transparent;
}

::-webkit-scrollbar-thumb {
  background: var(--text-muted);
  border-radius: var(--radius-pill);
}

::-webkit-scrollbar-thumb:hover {
  background: var(--text-secondary);
}

/* ─── Utility ────────────────────────────────────────────────────────────────── */

.hidden {
  display: none !important;
}

/* ─── App Shell ──────────────────────────────────────────────────────────────── */

#app {
  display: flex;
  height: 100%;
  overflow: hidden;
}

/* ─── Sidebar ────────────────────────────────────────────────────────────────── */

#sidebar {
  position: fixed;
  top: 0;
  left: 0;
  width: var(--sidebar-width);
  height: 100vh;
  background: var(--bg-surface);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  overflow-x: hidden;
  z-index: 100;
  transition: width var(--transition);
}

/* Sidebar: team header */
/* Match the top-bar height so the sidebar→main divider is one straight
   horizontal line instead of a step. box-sizing keeps the 1px border inside
   the height budget. Inner items are centered vertically. */
.sidebar-header {
  height: var(--top-bar-height);
  box-sizing: border-box;
  padding: 0 12px;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
  display: flex;
  align-items: center;
  gap: 8px;
}

.sidebar-team-name {
  font-family: var(--font-ui);
  font-size: 12px;
  font-weight: var(--fw-semibold);
  color: var(--text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.sidebar-team-meta {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
}

.sidebar-teammate-count {
  font-size: 10px;
  color: var(--text-muted);
}

/* ── Core picker ────────────────────────────────────────────────────────────
   Sits between the team brand row and the nav. Single button that opens a
   listbox of Cores. Switching a Core hits POST /api/cores/:id/activate, swaps
   the JWT, and hard-reloads so every view rebinds to the new Core's scope. */
.sidebar-core-picker-wrap {
  position: relative;
  padding: 10px 12px 4px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  gap: 6px;
}
.sidebar-core-picker {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 1;
  min-width: 0;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  padding: 5px 10px 5px 6px;
  font-family: var(--font-ui);
  font-size: 13px;
  font-weight: var(--fw-medium);
  color: var(--text-primary);
  cursor: pointer;
  text-align: left;
  transition: background var(--transition), border-color var(--transition);
}
.sidebar-core-picker:hover {
  background: var(--bg-hover);
  border-color: var(--border-strong, var(--border));
}
.sidebar-core-picker[aria-expanded="true"] {
  background: var(--bg-hover);
}
/* Trailing ⋯ on the Core picker — opens the active Core's edit page.
   Sits OUTSIDE the picker capsule so its click doesn't toggle the picker
   menu. Sizing matches the picker's vertical footprint (~28px). */
.sidebar-core-edit-btn {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  padding: 0;
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  color: var(--text-secondary);
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
  transition: background var(--transition), border-color var(--transition), color var(--transition);
}
.sidebar-core-edit-btn:hover {
  background: var(--bg-hover);
  border-color: var(--border);
  color: var(--text-primary);
}
.sidebar-core-picker-label {
  flex: 1;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* App-standard chevron — U+2303 ⌃ rotated via transform so stroke weight
   stays identical across orientations (matches the disclosure chevron in
   wiki.js). Closed = points down (rotate 180), open = points up (rotate 0).
   Animation is driven by the picker button's aria-expanded state, so the
   existing JS toggle is enough to flip the glyph. */
.sidebar-core-picker-chev {
  font-size: 1rem;
  line-height: 1;
  color: var(--text-secondary);
  flex-shrink: 0;
  display: inline-block;
  transform: rotate(180deg);
  transition: transform 120ms;
}
.sidebar-core-picker[aria-expanded="true"] .sidebar-core-picker-chev,
.top-bar-core-picker[aria-expanded="true"] .sidebar-core-picker-chev {
  transform: rotate(0deg);
}

.sidebar-core-menu {
  position: absolute;
  top: calc(100% - 2px);
  left: 12px;
  /* Widen beyond the picker capsule so the avatar + display name fit
     comfortably even for longer Core names. min-width sets the floor; the
     menu may still grow with the wrapper, and clamps to the viewport on
     narrow screens. */
  min-width: 240px;
  max-width: calc(100vw - 24px);
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.18);
  /* Float above sidebars, top bar, command palette, global-search dropdown,
     and rail content. Matches the top-bar Core menu (.top-bar-core-menu)
     and the global-search-results dropdown so all top-level dropdowns
     stack at the same tier. Modal overlays (1500+) still sit on top. */
  z-index: 1000;
  font-family: var(--font-ui);
}
.sidebar-core-menu.hidden { display: none; }
.sidebar-core-menu-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  background: transparent;
  border: 0;
  border-radius: var(--radius-sm);
  padding: 8px 10px;
  font-family: inherit;
  font-size: 13px;
  color: var(--text-primary);
  cursor: pointer;
  text-align: left;
}
.sidebar-core-menu-item:hover { background: var(--bg-hover); }
.sidebar-core-menu-item.is-active { color: var(--accent-blue); font-weight: var(--fw-semibold); }
.sidebar-core-menu-item:disabled { opacity: 0.5; cursor: default; }
.sidebar-core-menu-check {
  width: 14px;
  text-align: center;
  color: var(--accent-blue);
  font-size: 11px;
  flex-shrink: 0;
}
.sidebar-core-menu-new .sidebar-core-menu-check {
  color: var(--text-secondary);
  font-weight: var(--fw-bold);
}
.sidebar-core-menu-name {
  flex: 1;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.sidebar-core-menu-divider {
  height: 1px;
  background: var(--border);
  margin: 4px 2px;
}


/* Sidebar: nav */
.sidebar-nav {
  flex: 1;
  padding: 8px 0;
  overflow-y: auto;
}

.sidebar-group {
  margin-bottom: 4px;
}

.sidebar-group-label {
  padding: 6px 12px 3px;
  font-size: 10px;
  font-weight: var(--fw-semibold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.sidebar-nav-item {
  position: relative;
  display: flex;
  align-items: center;
  gap: 8px;
  /* Height matches the Core picker capsule directly above
     (.sidebar-core-picker: 18px avatar + 10px padding + 2px border = 30px),
     so the entire left rail reads as one consistent capsule column. The
     shared calc(6px + nudge) vertical padding still drives a ~26px
     content box; the explicit min-height pads it out to 30px without
     bumping the calc (which other rows like .sidebar-overflow-toggle
     copy from this pattern). */
  min-height: 30px;
  box-sizing: border-box;
  padding: calc(6px + var(--nav-spacing-offset)) 10px;
  /* Leading margin 18px puts the active dot ~6px from the sidebar's outer
     left edge — same column as the wiki rail's active-edit dot. Tighter
     than the previous 30px while still leaving the dot fully visible
     outside the capsule. */
  margin: 1px 6px 1px 18px;
  border-radius: var(--radius-pill);
  color: var(--text-primary);
  cursor: pointer;
  font-size: 13px;
  font-weight: var(--fw-medium);
  line-height: 1.2;
  transition: background var(--transition), color var(--transition);
  white-space: nowrap;
  overflow: visible;
  text-overflow: ellipsis;
  user-select: none;
  /* Transparent 1px baseline matches the facet rail rows
     (wiki.js buildSubRow/facet row) — same hairline language across the
     whole left rail, and the active state can paint its colored border
     without causing a 1px layout shift. */
  border: 1px solid transparent;
  background: none;
  text-align: left;
  width: calc(100% - 24px);
  font-family: var(--font-ui);
}

.sidebar-nav-item:hover {
  background: var(--bg-hover);
  color: var(--text-primary);
}

.sidebar-nav-item.active {
  /* Bg + border opacity track the same intensity sliders the facet rail uses
     (wiki.js buildSubRow / facet row). Multipliers match exactly:
       • bg     — clamp(0, --facet-selected-bg-intensity, 200) * 0.18%
       • border — clamp(0, --facet-selected-border-intensity, 200) * 0.5%
     Fallbacks match the :root defaults (100 / 40) so the main-nav active
     state and the facet rail's selected-row active state stay visually
     identical even when the user dials the sliders. */
  background: color-mix(
    in srgb,
    var(--accent-blue)
      calc(clamp(0, var(--facet-selected-bg-intensity, 100), 200) * 0.18%),
    transparent
  );
  border-color: color-mix(
    in srgb,
    var(--accent-blue)
      calc(clamp(0, var(--facet-selected-border-intensity, 40), 200) * 0.5%),
    transparent
  );
  color: var(--text-primary);
  font-weight: var(--fw-bold);
}

/* Active-state leading-edge indicator — small dot in the gutter to the
   left of the capsule, vertically centered. Mirrors the facets sidebar
   sub-row dot pattern (buildSubRow in wiki.js) so the whole app uses one
   active-indicator language. The bottom-tab-bar indicator below mirrors
   this dot for mobile. */
.sidebar-nav-item.active::before {
  content: '';
  position: absolute;
  left: -12px;
  top: 50%;
  width: 5px;
  height: 5px;
  margin-top: -2.5px;
  background: var(--accent-blue);
  border-radius: 50%;
  pointer-events: none;
}

/* Sidebar overflow ("⋯ More") — same nav-item chrome as the regular items
   but anchors a popover with Logs / Onboarding etc. The wrapper is
   position:relative so the menu can absolute-position relative to the
   toggle on desktop. */
.sidebar-overflow-wrap {
  position: relative;
}
.sidebar-overflow-menu {
  position: absolute;
  left: 8px;
  top: calc(100% + 6px);
  z-index: 50;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 6px;
  min-width: 180px;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.22);
}
.sidebar-overflow-menu.hidden {
  display: none;
}
.sidebar-overflow-option {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: calc(6px + var(--nav-spacing-offset)) 10px;
  border: none;
  background: transparent;
  border-radius: var(--radius-sm);
  color: var(--text-primary);
  font-family: var(--font-ui);
  font-size: 13px;
  font-weight: var(--fw-medium);
  line-height: 1.2;
  text-align: left;
  cursor: pointer;
}
.sidebar-overflow-option:hover {
  background: var(--bg-hover);
}

/* ─── Conversation detail header ────────────────────────────────────────────
   Desktop: members + actions inline as a single row at top-bar-height, the
   bottom border aligning with sibling headers (sidebar header, list-col
   New Chat sticky, viewHeader).
   Mobile (max-width: 767px): the two child rows stack — members row keeps
   top-bar-height with its own bottom border; actions row sits beneath at
   ~36px with another bottom border. CSS-only switch so the JS DOM stays
   identical across breakpoints (renderDetail builds both rows always). */
.conv-detail-header {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 10px;
  flex-shrink: 0;
  height: var(--top-bar-height);
  box-sizing: border-box;
  padding: 0 18px;
  border-bottom: 1px solid var(--border);
}
.conv-detail-header-row {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}
.conv-detail-header-row--members {
  flex: 1;
  flex-wrap: wrap;
}
.conv-detail-header-row--actions {
  flex-shrink: 0;
  justify-content: flex-end;
  margin-left: auto;
}

/* Sidebar-toggle icon (SF-symbol-style "sidebar.left"). Visible on every
   breakpoint — taps anchor to the leading edge of the actions row and
   toggle the conv-list-col via a class on .conv-body. Trailing action
   buttons (Distill / Delete / Merge) stay grouped on the trailing edge
   via Distill's `margin-left: auto` (set in JS).

   Visual treatment mirrors #wiki-rail-toggle (the hamburger that opens
   the facets drawer on the wiki page) — bordered elevated capsule, ☰
   glyph, primary text color. */
/* Optical centering — `‹›` glyphs render slightly below the bounding-box
   center because their visual mass sits at x-height. `padding-bottom: 2px`
   shrinks the inner content area, which (with align-items:center) shifts
   the glyph up 1px so its optical mid-line lines up with the adjacent
   label / title text instead of dropping below it. box-sizing:border-box
   keeps the outer 28×28 footprint unchanged (capsule-standard height). */
.conv-list-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0 0 2px;
  box-sizing: border-box;
  /* Full circle + visible border + raised surface so the toggle reads as
     a real button against the panel in both light and dark themes. The
     prior bg-hover-only fill disappeared into the surrounding surface. */
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 999px;
  color: var(--text-primary);
  font-size: 17px;
  font-weight: var(--fw-semibold);
  line-height: 1;
  cursor: pointer;
  transition: background 120ms, border-color 120ms;
  flex-shrink: 0;
}
.conv-list-toggle:hover {
  background: var(--bg-hover);
  border-color: var(--text-muted);
}
/* Hides the conversation list column when the toggle is engaged. Applies
   on every breakpoint. !important is required — conv-list-col carries an
   inline `display: flex` set in JS, and inline styles beat class
   selectors without it. */
.conv-body.conv-list-hidden .conv-list-col {
  display: none !important;
}

/* Chain-mode silent rows. Two flavors:
   - .chain-silent-row--per-facet: one facet stayed silent (avatar + "X stayed
     silent" label, click "why?" expands the reason inline).
   - .chain-silent-row (no modifier): all-silent fallback (summary + per-facet
     reasons list). Both share the muted-text + rounded-tint look so the row
     visually belongs in the transcript at any --radius scale, instead of
     reading as a flat strip beside rounded peers (P2 #16). */
.chain-silent-row {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--bg-elevated) 50%, transparent);
  border: 1px solid color-mix(in srgb, var(--border) 60%, transparent);
  color: var(--text-muted);
  font-size: 0.78rem;
  font-family: var(--font-ui);
  font-style: italic;
  position: relative;
}
.chain-silent-row--per-facet {
  flex-direction: row;
  align-items: center;
  gap: 8px;
}
.chain-silent-row__summary {
  color: var(--text-secondary);
  font-style: normal;
  line-height: 1.45;
}
.chain-silent-row__toggle {
  align-self: flex-start;
  background: transparent;
  border: 0;
  padding: 0;
  font: inherit;
  color: var(--text-muted);
  cursor: pointer;
  text-decoration: underline dotted;
}
.chain-silent-row__details {
  display: none;
  margin: 4px 0 0;
  padding: 0 0 0 16px;
  list-style: disc;
  color: var(--text-secondary);
  font-style: normal;
  line-height: 1.5;
}
.chain-silent-row__details > li {
  margin: 2px 0;
}
.chain-silent-row__label {
  font-size: 0.78rem;
  color: var(--text-muted);
  font-style: italic;
}
.chain-silent-row__why {
  background: transparent;
  border: 0;
  padding: 0 4px;
  font-size: 0.72rem;
  color: var(--text-muted);
  cursor: pointer;
  text-decoration: underline dotted;
  font-family: var(--font-ui);
}
.chain-silent-row__reason {
  font-size: 0.75rem;
  color: var(--text-muted);
  font-style: italic;
  display: none;
}
.chain-silent-row__ts {
  margin-left: auto;
  font-size: 0.7rem;
  font-style: italic;
  color: var(--text-muted);
  font-family: var(--font-ui);
  flex-shrink: 0;
}

/* Conversation-list multi-participant avatar stack — desktop has plenty of
   horizontal room, so each avatar overlaps its predecessor by 7px. Mobile
   tightens the overlap to 11px so the "{N} members" label still has room
   beside the stack on a 320px-wide phone. */
.conv-list-avatar-stack > *:not(:first-child) {
  margin-left: -7px;
}
@media (max-width: 767px) {
  .conv-list-avatar-stack > *:not(:first-child) {
    margin-left: -11px;
  }
  /* Cap the visible avatar stack at 5 on phone — JS still renders up to
     7 (sorted by most-recent-activity by the worker), but the trailing
     ones hide so the count + chev capsule fits in a 320px row.
     `!important` is required because `buildAvatar` sets `display:
     inline-flex` as an inline style on each avatar wrap, and inline
     styles beat class selectors without it. */
  .conv-list-avatar-stack > *:nth-child(n+6) {
    display: none !important;
  }
  /* Drop the "members" suffix on phone — the trailing chevron already
     signals the popover affordance, and the bare count + chevron leaves
     more room for the topic line beside the row. */
  .conv-list-members-word {
    display: none;
  }
  /* Drop the relative-time stamp on phone — list rows are too narrow to
     keep the timestamp + members capsule on the same line, and the topic
     row below is the higher-value information. */
  .conv-list-ts {
    display: none;
  }
}

@media (max-width: 767px) {
  /* Mobile shows the members row inline alongside the toggle + actions, so
     the avatar (single-participant) or participants capsule (multi) is
     visible at the top of every conversation. Lock to nowrap + min-width:0
     so long names truncate via ellipsis rather than wrapping to a second
     line and breaking the top-bar-height row. */
  .conv-detail-header-row--members {
    flex-wrap: nowrap;
    min-width: 0;
    overflow: hidden;
  }
}

.sidebar-nav-item .nav-icon {
  font-size: 15px;
  flex-shrink: 0;
  width: 18px;
  text-align: center;
}

.sidebar-nav-item .nav-label {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Sidebar: decorative auto-rotating render (Blender) */
.sidebar-render {
  flex-shrink: 0;
  display: flex;
  justify-content: center;
  padding: 12px 0;
}
.sidebar-render video {
  width: 100%;
  max-width: 180px;
  height: auto;
  display: block;
  pointer-events: none;
}

/* Sidebar: footer */
.sidebar-footer {
  flex-shrink: 0;
  padding: 10px 8px;
  border-top: 1px solid var(--border);
}

/* ─── Top Bar ────────────────────────────────────────────────────────────────── */

#top-bar {
  position: fixed;
  top: 0;
  left: var(--sidebar-width);
  right: 0;
  height: var(--top-bar-height);
  background: var(--bg-surface);
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 16px;
  z-index: 90;
  gap: 12px;
  transition: left var(--transition);
}

.top-bar-left {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-shrink: 1;
  min-width: 0;
}

.top-bar-logo {
  font-family: var(--font-ui);
  font-size: 13px;
  font-weight: var(--fw-bold);
  color: var(--text-primary);
  letter-spacing: -0.02em;
}

/* Mobile-only wordmark in the top-bar-left slot. Desktop hides it (the
   brand belongs on the login page / sidebar header on desktop, not the
   top bar). */
.top-bar-brand {
  display: none;
  font-family: var(--font-ui);
  font-weight: var(--fw-semibold);
  font-size: 0.95rem;
  color: var(--text-primary);
  letter-spacing: -0.01em;
  white-space: nowrap;
}

/* Tiny muted version stamp tucked under the global search input on desktop.
   Absolute-positioned inside .top-bar-search (which is position:relative),
   right-aligned so it sits unobtrusively at the trailing edge. Mobile hides
   it entirely — mobile users see Version inside the bottom-tab "More" menu. */
/* Sidebar footer — version + build, sticky at the bottom of the desktop
   sidebar. Mobile shows this info inside the bottom-tab "More" menu instead
   (the desktop sidebar is hidden on mobile by an existing @media rule). */
.sidebar-footer {
  margin-top: auto;
  padding: 10px 14px 14px;
  font-size: 0.62rem;
  color: var(--text-muted);
  font-family: var(--font-ui);
  letter-spacing: 0.01em;
  border-top: 1px solid var(--border);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.top-bar-center {
  flex: 1;
  display: flex;
  justify-content: center;
  min-width: 0;
}

/* Page-title slot inside the top bar — leading side of the global search.
   Replaces the per-view .nav-page-header rows on the five main nav pages
   (Discover / Facets / Conversations / Account / Help). Populated by
   app.js navigate() from a VIEW_META map. Shrinks to allow the search
   field to expand into the free space; tagline ellipses then drops on
   narrow viewports (see the mobile rule below). */
.top-bar-page {
  display: flex;
  align-items: baseline;
  gap: 8px;
  min-width: 0;
  flex: 0 1 auto;
  font-family: var(--font-ui);
  color: var(--text-primary);
  white-space: nowrap;
  overflow: hidden;
}
.top-bar-page:empty { display: none; }
.top-bar-page-title {
  font-size: 1rem;
  font-weight: var(--fw-semibold);
  letter-spacing: -0.01em;
  flex-shrink: 0;
}
.top-bar-page-sep {
  color: var(--text-primary);
  opacity: 0.4;
  flex-shrink: 0;
}
.top-bar-page-sub {
  font-size: 0.8rem;
  color: var(--text-primary);
  opacity: 0.7;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

.top-bar-breadcrumb {
  display: flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-ui);
  font-size: 12px;
  color: var(--text-secondary);
  white-space: nowrap;
}

.top-bar-breadcrumb-sep {
  color: var(--text-muted);
}

#top-bar-view {
  color: var(--text-primary);
}

.top-bar-right {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}

/* Global search — sits inside .top-bar-right as a 36px circular trigger
   between the wiki/page area and the theme toggle. Tapping the icon focuses
   the hidden input, which adds .is-search-expanded to #top-bar and the
   wrapper grows to fill the available row. Dropdown anchors to the input
   and overflows the top bar via absolute positioning. */
.top-bar-search {
  position: relative;
  flex: 0 0 36px;
  width: 36px;
  max-width: 36px;
  height: 36px;
  display: flex;
  align-items: center;
  transition: flex-basis 240ms ease, max-width 240ms ease, width 240ms ease;
}
.top-bar-search .pill-composer {
  width: 36px;
  height: 36px;
  min-height: 36px;
  border-radius: 999px;
  padding: 0;
  overflow: hidden;
  position: relative;
  transition:
    width 240ms ease,
    border-radius 240ms ease,
    padding 240ms ease,
    background-color 240ms ease;
}
/* Magnifier icon — pure CSS via SVG mask so it inherits text color and
   animates with the wrapper. */
.top-bar-search .pill-composer::before {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 16px;
  height: 16px;
  background-color: var(--text-primary);
  -webkit-mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' d='M7 7m-4 0a4 4 0 1 0 8 0a4 4 0 1 0 -8 0'/><path fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' d='M10 10l4 4'/></svg>");
          mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' d='M7 7m-4 0a4 4 0 1 0 8 0a4 4 0 1 0 -8 0'/><path fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' d='M10 10l4 4'/></svg>");
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
  -webkit-mask-position: center;
          mask-position: center;
  transition: left 240ms ease, transform 240ms ease;
  pointer-events: none;
}
/* Hide the input text + placeholder while collapsed; the wrapper acts as the
   tap target (focus still fires because the input is the only focusable
   child). */
#global-search-input {
  width: 100%;
  box-sizing: border-box;
  color: transparent;
  caret-color: transparent;
  padding: 0 0 0 36px;
  border: 0;
  background: transparent;
  height: 100%;
  cursor: pointer;
}
.top-bar-search #global-search-input::placeholder { color: transparent; }

/* Expanded — JS toggles .is-search-expanded on focus. Wrapper grows to a
   comfortable search width on desktop / fills the row on mobile so the
   results dropdown has room to breathe. */
#top-bar.is-search-expanded .top-bar-search {
  /* Fill all available width in the row when active. Other right-cluster
     siblings (theme toggle) keep their natural space; the search takes
     the rest. Mobile @media block hides the left cluster too so the
     search really spans the whole bar there. */
  flex: 1 1 auto;
  width: auto;
  max-width: none;
}
/* Yield the row to the search on expansion: drop the page-title slot
   (the center spacer) and let the right cluster grow into the freed
   space. Without this the .top-bar-center { flex: 1 } rule keeps
   hoarding the spare width and the search can't actually widen.
   The .top-bar-left cluster stays visible on desktop so the user can
   still see/click the sidebar trigger; only .top-bar-center collapses. */
#top-bar.is-search-expanded .top-bar-center {
  display: none;
}
#top-bar.is-search-expanded .top-bar-right {
  flex: 1 1 auto;
  min-width: 0;
}
#top-bar.is-search-expanded .top-bar-search .pill-composer {
  width: 100%;
  border-radius: var(--radius-sm);
  padding: 0;
}
#top-bar.is-search-expanded .top-bar-search .pill-composer::before {
  left: 12px;
  transform: translate(0, -50%);
}
#top-bar.is-search-expanded .top-bar-search #global-search-input {
  color: var(--text-primary);
  caret-color: var(--text-primary);
  padding: 0 12px 0 36px;
  cursor: text;
}
#top-bar.is-search-expanded .top-bar-search #global-search-input::placeholder {
  color: var(--text-secondary);
}
.global-search-results {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  right: 0;
  max-height: 60vh;
  overflow-y: auto;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: 0 10px 28px rgba(0,0,0,0.22);
  z-index: 1000;
  font-family: var(--font-ui);
}
.global-search-section {
  padding: 6px 0;
}
.global-search-section + .global-search-section {
  border-top: 1px solid var(--border);
}
.global-search-section-header {
  font-size: 0.66rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-muted);
  font-weight: var(--fw-semibold);
  padding: 6px 12px 4px;
}
.global-search-result {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 8px 12px;
  cursor: pointer;
  border: none;
  background: transparent;
  text-align: left;
  width: 100%;
  color: var(--text-primary);
  font-family: var(--font-ui);
}
.global-search-result:hover,
.global-search-result.is-active {
  background: var(--bg-hover);
}
.global-search-result-title {
  font-size: 13px;
  font-weight: var(--fw-semibold);
  color: var(--text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.global-search-result-meta {
  font-size: 11px;
  color: var(--text-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Mail-style — quiet group header, leading colored dot, right-aligned meta. */
.gsr-group {
  padding: 4px 0 6px;
}
.gsr-group + .gsr-group {
  border-top: 1px solid var(--border);
  margin-top: 2px;
}
.gsr-group-header {
  font-size: 11px;
  font-weight: var(--fw-semibold);
  color: var(--text-muted);
  padding: 8px 14px 4px;
}
.global-search-result.gsr-row {
  flex-direction: row;
  align-items: center;
  gap: 10px;
  padding: 7px 14px;
}
.gsr-dot {
  flex: none;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--text-muted);
  margin: 0 2px;
}
.gsr-row--conv .gsr-dot { background: var(--accent-blue); }
.gsr-row--wiki .gsr-dot { background: var(--accent-green); }
.gsr-body {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 1px;
}
.gsr-title {
  font-size: 13px;
  font-weight: var(--fw-semibold);
  color: var(--text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.gsr-snippet {
  font-size: 11.5px;
  color: var(--text-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  line-height: 1.4;
}
.gsr-meta {
  flex: none;
  margin-left: 10px;
  font-size: 11px;
  color: var(--text-muted);
  white-space: nowrap;
}
.global-search-empty {
  padding: 14px 14px 16px;
  font-size: 12px;
  color: var(--text-secondary);
}
.global-search-result.is-more {
  opacity: 0.7;
}
.global-search-more-toggle {
  display: block;
  width: 100%;
  background: transparent;
  border: none;
  text-align: left;
  cursor: pointer;
  padding: 6px 12px;
  color: var(--text-muted);
  font-family: var(--font-ui);
  font-size: 11px;
  font-style: italic;
}
.global-search-more-toggle:hover {
  color: var(--text-primary);
  background: var(--bg-hover);
}
.global-search-loading {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 14px 14px 16px;
  font-size: 12px;
  color: var(--text-secondary);
  font-family: var(--font-ui);
}
.global-search-spinner {
  width: 14px;
  height: 14px;
  border: 2px solid var(--border);
  border-top-color: var(--accent-blue);
  border-radius: 50%;
  animation: global-search-spin 0.7s linear infinite;
  flex-shrink: 0;
}
@keyframes global-search-spin {
  to { transform: rotate(360deg); }
}

/* Default: mobile Core picker hidden on desktop. The @media (max-width: 767px)
   block immediately below flips this to display:flex on mobile. Rule MUST sit
   ABOVE the @media block so the cascade resolves correctly — placing it after
   the @media block (as it was originally) made source-order beat the matching
   media rule on mobile too, hiding the picker. */
.top-bar-core-picker-mobile { display: none; }

/* Mobile — let the search bar fill the available row (flex:1 + min-width:0
   from the desktop rule already does the work; we just don't cap it here).
   The is-search-expanded path below still hides the side clusters when the
   user is actively searching so the dropdown gets the whole row. */
@media (max-width: 767px) {
  /* iOS Safari auto-zooms any input with computed font-size < 16px on focus.
     Force 16px on mobile to keep the viewport stable when the user taps in. */
  #global-search-input {
    font-size: 16px;
  }
  .top-bar-team-name { display: none; }
  /* Brand wordmark — shown on mobile, absolutely centered inside the fixed
     #top-bar so the leading (Core picker) and trailing (search, settings)
     clusters can flow naturally with the flex layout without fighting the
     centered glyph. pointer-events:none lets taps fall through to whatever
     control sits behind it. */
  .top-bar-brand {
    display: block;
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    pointer-events: none;
    user-select: none;
    z-index: 1;
  }
  /* When the search field expands to fill the row, the brand would sit on
     top of the input — hide it for the duration of the expanded state. */
  #top-bar.is-search-expanded .top-bar-brand { display: none; }
  /* Mobile-only Core picker mount. The desktop sidebar copy is hidden
     here because the sidebar itself is hidden on mobile by the existing
     layout rule. */
  .top-bar-core-picker-mobile { display: flex; align-items: center; }

  /* Mobile-expanded search: hide side clusters and let the input fill the
     row so the results dropdown isn't crowded by other top-bar chrome. The
     collapsed-circle baseline + the desktop-expanded width are defined at
     the universal selectors above; this block only specializes the
     expanded variant for narrow viewports. */
  #top-bar.is-search-expanded .top-bar-left,
  #top-bar.is-search-expanded .top-bar-right > *:not(.top-bar-search) {
    display: none;
  }
  #top-bar.is-search-expanded .top-bar-search {
    flex: 1 1 auto;
    max-width: none;
  }

  /* The whole top-bar page slot is dropped on narrow viewports — the
     active row/section is already implied by the bottom-tab-bar selection
     and the in-view chrome, so the title + tagline are noise eating
     horizontal room the search and Core picker need. */
  .top-bar-page-title,
  .top-bar-page-sep,
  .top-bar-page-sub {
    display: none;
  }
  /* Mobile Core picker collapses to avatar + chevron — the Core name
     repeats info already visible in the bottom-tab-bar / page chrome and
     just steals top-bar width. The dropdown still lists names normally. */
  .top-bar-core-picker .sidebar-core-picker-label {
    display: none;
  }
}

/* Mobile Core-picker styling. Reuses most of the desktop picker visuals,
   just dropped into the top bar instead of the sidebar header. The
   default-display rule lives ABOVE the @media block (see the mobile
   picker selector inside the @media block at the top of styles.css) so
   the @media-scoped 'display: flex' wins via source order on mobile. */
.top-bar-core-picker-mobile .top-bar-core-picker-wrap {
  position: relative;
  display: flex;
  align-items: center;
  gap: 4px;
}
.top-bar-core-picker {
  display: flex;
  align-items: center;
  gap: 6px;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  /* Locked to 36px to match the global search button's collapsed circle
     height — same visual control affordance in the top bar. */
  height: 36px;
  box-sizing: border-box;
  padding: 0 10px 0 6px;
  font-family: var(--font-ui);
  font-size: 13px;
  font-weight: var(--fw-medium);
  color: var(--text-primary);
  cursor: pointer;
  max-width: 180px;
}
.top-bar-core-picker:hover { background: var(--bg-hover); }
.top-bar-core-picker[aria-expanded="true"] { background: var(--bg-hover); }
/* Mobile ⋯ edit button next to the picker — sized to match the picker /
   search button (36×36) for a consistent top-bar control row. The base
   .sidebar-core-edit-btn rule keeps its smaller desktop sizing. */
.top-bar-core-picker-mobile .sidebar-core-edit-btn {
  width: 36px;
  height: 36px;
  font-size: 16px;
}
.top-bar-core-menu {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  min-width: 240px;
  max-width: calc(100vw - 24px);
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.18);
  padding: 6px;
  z-index: 1000;
}

.top-bar-team-name {
  font-size: 11px;
  color: var(--text-secondary);
  white-space: nowrap;
}

.theme-toggle-btn {
  /* Background + border mirror .pill-composer so the gear reads as the
     same chrome family as the global search trigger sitting next to it
     in the top bar. */
  background: var(--bg-base);
  border: 1px solid var(--border);
  color: var(--text-secondary);
  cursor: pointer;
  width: 36px;
  height: 36px;
  border-radius: 999px;
  font-size: 16px;
  line-height: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: background var(--transition), color var(--transition), border-color var(--transition);
  padding: 0;
}
.theme-toggle-btn:hover {
  background: var(--bg-hover);
  color: var(--accent-blue);
  border-color: var(--accent-blue);
}

/* Conversation list column — sets the em baseline for all rows. Inline
   font-size:Xem inside buildListItem multiplies against this. */
.conv-list-col {
  font-size: calc(15px * var(--conv-list-scale-desktop, 1));
}

/* Conversation list rows — selection indicator is a capsule pill in a
   reserved leading gutter. The row's inline `padding:12px 14px 12px 20px`
   (set in buildListItem) carves out the gutter; unselected rows keep the
   indent so cards don't jitter horizontally when the active row changes.
   The pill itself is drawn by ::before on the --active / --pinned-profile
   modifiers. Width/position are stable across states — only the color
   (transparent → accent) transitions. */
.conv-list-item {
  position: relative;
}
.conv-list-item::before {
  content: '';
  position: absolute;
  left: 6px;
  top: 18%;
  bottom: 18%;
  width: 3px;
  border-radius: 999px;
  background: transparent;
  transform: scaleY(0.2);
  transform-origin: center;
  transition: background var(--transition), transform 280ms cubic-bezier(0.4, 0, 0.2, 1);
  pointer-events: none;
}
.conv-list-item--active::before,
.conv-list-item--pinned-profile::before {
  background: var(--accent-blue);
  transform: scaleY(1);
}

/* ─── Main Content ───────────────────────────────────────────────────────────── */

#main-content {
  margin-left: var(--sidebar-width);
  padding-top: var(--top-bar-height);
  height: 100vh;
  flex: 1;
  overflow: hidden;
}

/* ─── Bottom Tab Bar (mobile only) ─────────────────────────────────────────────
   Hidden on desktop; the @media (max-width: 767px) block flips it on. Lives
   here at top-level so the desktop default is `display: none`. */
#bottom-tab-bar {
  display: none;
}

/* ─── Views ──────────────────────────────────────────────────────────────────── */

.view {
  display: none;
  flex-direction: column;
  height: 100%;
  overflow-y: auto;
  animation: view-fade-in 180ms ease;
}

.view.active {
  display: flex;
}

@keyframes view-fade-in {
  from {
    opacity: 0;
    transform: translateY(6px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* ─── Layout: View Sections ──────────────────────────────────────────────────── */

/* ── .page-header ──────────────────────────────────────────────────────────
   Canonical page-level header. One row, vertically centered, with a divider.
   Tuned via the --page-header-* tokens in :root above. Used at the top of
   every primary view (Conversations, Discover, Account, Help) and every
   wiki center-panel sub-mode (Chat, Identity, Edit, Sources). The mobile
   @media block further down forces this same selector to a 40px row inline
   with the wiki hamburger toggle. */
/* Fixed height read from --page-header-height — the single knob for the
   chrome row across the 5 main-nav pages. Defaults match --top-bar-height
   so other internal alignments (sidebar header, conversation thread header)
   stay flush by default; the user can decouple via the dev GUI if they want
   a different page-header height. Vertical padding is zero — flex centering
   handles content alignment. Mobile override applies in the media query. */
.page-header {
  height: var(--page-header-height);
  box-sizing: border-box;
  padding: 0 var(--page-header-padding-x);
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  gap: 10px;
  flex-shrink: 0;
}

.page-header h1,
.page-header h2,
.page-header h3 {
  margin: 0;
  font-size: var(--page-header-title-size);
  font-weight: var(--fw-semibold);
  color: var(--text-primary);
  font-family: var(--font-ui);
}

/* Height-only override applied to the 5 main-nav pages (Discover, Facets,
   Conversations, Account, Help). They keep .page-header for the shared
   padding/border/flex base and add .nav-page-header to opt into the
   independently-tunable shorter chrome height. */
.nav-page-header {
  height: var(--nav-page-header-height);
}

/* Legacy alias — old call sites used .view-header. Kept so any straggler
   references still get the canonical styling. New code should use .page-header. */
.view-header {
  padding: var(--page-header-padding-y) var(--page-header-padding-x);
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}

.view-header h1,
.view-header h2 {
  font-size: var(--page-header-title-size);
  font-weight: var(--fw-semibold);
  color: var(--text-primary);
  margin: 0;
}

.view-header p {
  font-size: 12px;
  color: var(--text-secondary);
}

.view-body {
  flex: 1;
  padding: 20px 24px;
  overflow-y: auto;
}

/* ─── Cards ──────────────────────────────────────────────────────────────────── */

.card {
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 16px;
  transition: border-color var(--transition);
}

.card:hover {
  border-color: var(--text-muted);
}

.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 16px;
}

.card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 8px;
  gap: 8px;
}

.card-header .card-name {
  font-size: 13px;
  font-weight: var(--fw-semibold);
  color: var(--text-primary);
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.card-body {
  font-size: 12px;
  color: var(--text-secondary);
  line-height: 1.5;
  margin-bottom: 12px;
}

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

.card--empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 48px 24px;
  text-align: center;
  color: var(--text-muted);
  font-size: 12px;
  border-style: dashed;
}

.card--empty .empty-icon {
  font-size: 31px;
  margin-bottom: 12px;
  opacity: 0.5;
}

/* ─── Buttons ────────────────────────────────────────────────────────────────── */

/* Capsule standard — mirrors the wiki sub-row template (buildSubRow in
   components/wiki.js). Renders ~28px tall on default --nav-spacing-offset,
   matching the sidebar Identity/Wiki sub-rows and the sticky New / New Facet
   CTAs. Every full-size .btn now reads in the same height family. Use
   .btn-sm / .btn-xs for deliberately smaller variants. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: calc(6px + var(--nav-spacing-offset)) 10px;
  border-radius: var(--radius-pill);
  font-size: 13px;
  font-weight: var(--fw-medium);
  font-family: var(--font-ui);
  cursor: pointer;
  border: 1px solid transparent;
  transition: background var(--transition), color var(--transition),
              border-color var(--transition), opacity var(--transition);
  line-height: 1.2;
  min-height: 0;
  white-space: nowrap;
  user-select: none;
  letter-spacing: -0.01em;
}

.btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
  outline: none;
  box-shadow: none;
}

.btn-primary {
  background: var(--accent-blue);
  color: #fff;
  border-color: var(--accent-blue);
}

.btn-primary:hover:not(:disabled) {
  background: #2D94FF;
  border-color: #2D94FF;
}

/* Legacy compact modifier. With the new capsule-standard baseline on .btn,
   .btn-compact is now visually equivalent to base .btn — the class is kept
   so existing markup doesn't break, but it no longer alters sizing. */
.btn-compact {
  /* no-op — inherits capsule-standard from .btn */
}

/* Full-width modifier — combine with .btn for sticky list-header "New"
   (conversations) and sidebar "New Facet" (wiki rail) rows. Pure width
   modifier; sizing comes from the capsule-standard .btn baseline. */
.btn-block {
  width: 100%;
  min-height: 0;
  box-sizing: border-box;
}

.btn-danger {
  background: var(--accent-red);
  color: #fff;
  border-color: var(--accent-red);
}

.btn-danger:hover:not(:disabled) {
  background: #ff6b6b;
  border-color: #ff6b6b;
}

.btn-ghost {
  background: transparent;
  color: var(--text-secondary);
  border-color: transparent;
}

.btn-ghost:hover:not(:disabled) {
  background: var(--bg-hover);
  color: var(--text-primary);
  border-color: var(--border);
}

.btn-sm {
  padding: 6px 13px;
  font-size: 11px;
  border-radius: var(--radius-pill);
}

.btn-xs {
  padding: 4px 10px;
  font-size: 10px;
  border-radius: var(--radius-pill);
}

.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  border: 1px solid transparent;
  color: var(--text-secondary);
  cursor: pointer;
  transition: background var(--transition), color var(--transition), border-color var(--transition);
  font-size: 13px;
}

.icon-btn:hover {
  background: var(--bg-hover);
  color: var(--text-primary);
  border-color: var(--border);
}

/* ─── Terminal ───────────────────────────────────────────────────────────────── */

.terminal {
  background: var(--bg-base);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 14px 16px;
  font-family: var(--font-mono);
  font-size: 12px;
  line-height: 1.6;
  overflow-x: auto;
}

.terminal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 10px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--border);
  color: var(--text-secondary);
  font-size: 11px;
}

.terminal-line {
  color: var(--text-primary);
  white-space: pre-wrap;
  word-break: break-all;
}

.terminal-line + .terminal-line {
  margin-top: 2px;
}

.terminal-line--system {
  color: var(--text-muted);
}

.terminal-line--error {
  color: var(--accent-red);
}

/* ─── Discussion turn cards ─────────────────────────────────────────────── */

.discussion-turn {
  margin: 8px 0;
  border: 1px solid var(--border);
  border-left: 3px solid var(--turn-color, var(--accent-blue));
  border-radius: var(--radius-sm);
  background: var(--bg-elevated);
  overflow: hidden;
}

.discussion-turn__header {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 12px;
  border-bottom: 1px solid var(--border);
  background: var(--bg-card);
}

.discussion-turn__dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--turn-color, var(--accent-blue));
  flex-shrink: 0;
}

.discussion-turn__name {
  font-size: 0.82rem;
  font-weight: var(--fw-bold);
  color: var(--turn-color, var(--accent-blue));
  flex: 1;
  font-family: var(--font-ui);
}

.discussion-turn__time {
  font-size: 0.72rem;
  color: var(--text-muted);
  font-family: var(--font-ui);
}

.discussion-turn__body {
  padding: 10px 14px;
  font-size: 0.82rem;
  line-height: 1.65;
  color: var(--text-primary);
  font-family: var(--font-ui);
  white-space: pre-wrap;
}

.terminal-line--success {
  color: var(--accent-green);
}

/* ─── Badges ─────────────────────────────────────────────────────────────────── */

.badge {
  display: inline-flex;
  align-items: center;
  padding: 2px 7px;
  border-radius: var(--radius-pill);
  font-size: 10px;
  font-weight: var(--fw-medium);
  font-family: var(--font-ui);
  line-height: 1.4;
  white-space: nowrap;
  letter-spacing: 0.02em;
}

.badge--leader {
  background: rgba(210, 153, 34, 0.15);
  color: var(--accent-orange);
  border: 1px solid rgba(210, 153, 34, 0.3);
}

.badge--env-dev {
  background: rgba(88, 166, 255, 0.12);
  color: var(--accent-blue);
  border: 1px solid rgba(88, 166, 255, 0.25);
}

.badge--env-prod {
  background: rgba(63, 185, 80, 0.12);
  color: var(--accent-green);
  border: 1px solid rgba(63, 185, 80, 0.25);
}

.badge--facet {
  background: rgba(188, 140, 255, 0.12);
  color: var(--accent-purple);
  border: 1px solid rgba(188, 140, 255, 0.25);
}

/* ─── Forms ──────────────────────────────────────────────────────────────────── */

.form-group {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-bottom: 16px;
}

.form-group label {
  font-size: 11px;
  font-weight: var(--fw-semibold);
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.input {
  width: 100%;
  padding: 8px 14px;
  min-height: var(--input-height);
  box-sizing: border-box;
  background: var(--bg-base);
  border: 1px solid var(--border);
  border-radius: 999px;
  color: var(--text-primary);
  font-family: var(--font-ui);
  font-size: 12px;
  outline: none;
  transition: border-color var(--transition), box-shadow var(--transition);
}

.input:focus {
  border-color: var(--accent-blue);
  box-shadow: 0 0 0 3px rgba(88, 166, 255, 0.12);
}

/* Unified focus glow for every text-entry surface — the canonical look the
   user expects when they click into ANY input. Buttons, segmented toggles
   styled as buttons, color pickers, and contentEditable surfaces with their
   own focus handlers are intentionally excluded.
   Note: inline `border:` declarations on textareas (chat composers) win over
   `border-color` here due to inline-style precedence — those inputs had
   their inline border pulled out so this rule wins. */
input[type="text"]:focus,
input[type="search"]:focus,
input[type="email"]:focus,
input[type="password"]:focus,
input[type="number"]:focus,
input[type="url"]:focus,
input[type="tel"]:focus,
input:not([type]):focus,
textarea:focus,
.input:focus,
.textarea:focus {
  border-color: var(--accent-blue);
  box-shadow: 0 0 0 3px rgba(88, 166, 255, 0.12);
}

input:disabled,
textarea:disabled,
.input:disabled,
.textarea:disabled {
  opacity: 0.55;
  box-shadow: none;
}

.input::placeholder {
  color: var(--text-primary);
  opacity: 0.5;
}

.textarea {
  width: 100%;
  padding: 10px 14px;
  box-sizing: border-box;
  background: var(--bg-base);
  border: 1px solid var(--border);
  /* Matches conversation message-bubble radius (--radius-sm = 16px) so a
     multi-line input reads as the same rounded-rect shape as the bubble it
     produces. At single-line height (~36px) the 16px corners still read as
     a near-pill; once expanded past ~48px (≈2 lines) it's a clean rounded
     rect with the bubble-matching corner. */
  border-radius: var(--radius-sm);
  color: var(--text-primary);
  font-family: var(--font-ui);
  font-size: 12px;
  outline: none;
  resize: vertical;
  /* Default multiline floor; per-instance overrides downshift via inline
     min-height (e.g. blurb 52px, description 64px) but never below
     var(--input-height). */
  min-height: var(--input-height);
  line-height: 1.6;
  transition: border-color var(--transition), box-shadow var(--transition);
}

.textarea:focus {
  border-color: var(--accent-blue);
  box-shadow: 0 0 0 3px rgba(88, 166, 255, 0.12);
}

/* Shared autosize behavior — see components/autosize.js. The helper writes
   data-autosize-shape="single" (1 line of content) or "multi" (2-3 lines)
   onto the "paint target" (the wrapper that carries the visible border, or
   the textarea itself when there is no wrapper). At 4+ lines the textarea
   height locks and the helper enables internal scrolling.
   The CSS only has to pick the right border-radius per shape. */
/* Specificity note: combined with .autosize-paint so these rules beat the
   per-surface .composer-textarea / .pill-composer / .onb-vignette-* border-
   radius declarations. Painted elements opt in by being passed to the helper. */
/* Multi-line radius matches the conversation message-bubble radius
   (--radius-sm) — see textEl border-radius in conversations.js. The visual
   contract: a multi-line input reads as the same rounded-rect shape as the
   message bubble it produces. */
.autosize-paint[data-autosize-shape='single'] { border-radius: var(--radius-pill, 999px); }
.autosize-paint[data-autosize-shape='multi']  { border-radius: var(--radius-sm, 16px); }
/* Smooth the corner morph as content crosses the 1↔2 line threshold. */
.autosize-paint { transition: border-radius 140ms ease, border-color 120ms; }
/* Textareas governed by the helper should never show the OS resize handle —
   the user resizes by typing, not by dragging. */
textarea.autosize-input { resize: none; }

/* Chat-style composer textarea — used in conversations.js and wiki.js
   Core/facet chat. Owns the full sizing/typography spec so callers only
   need `flex:1` (which is layout-context-specific). The unified
   textarea:focus rule above paints the blue border + glow on focus. */
.composer-textarea {
  background: var(--bg-base);
  border: 1px solid var(--border);
  /* See .textarea note: matches the conversation message-bubble radius
     (--radius-sm). 16px reads as near-pill at single-line height (~36px tall),
     and as a clean rounded rect once it grows past ~2 lines. */
  border-radius: var(--radius-sm);
  color: var(--text-primary);
  outline: none;
  transition: border-color var(--transition), box-shadow var(--transition);
  padding: 8px 10px;
  font-size: 0.85rem;
  font-family: var(--font-ui);
  resize: none;
  overflow-y: hidden;
  min-height: var(--input-height);
  max-height: 160px;
  line-height: 1.45;
}

/* Wiki inline inputs (ingest paste, filter, query) — same role as
   .composer-textarea but for the wiki view's smaller controls.
   inputCss() above writes the cssText; this class supplies the look. */
.wiki-inline-input {
  background: var(--bg-base);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text-primary);
  outline: none;
  transition: border-color var(--transition), box-shadow var(--transition);
}

.textarea::placeholder {
  color: var(--text-primary);
  opacity: 0.5;
}

.chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 10px;
  border-radius: var(--radius-pill);
  font-size: 11px;
  font-family: var(--font-ui);
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  color: var(--text-secondary);
  cursor: pointer;
  transition: background var(--transition), color var(--transition), border-color var(--transition);
  user-select: none;
}

.chip:hover {
  background: var(--bg-hover);
  color: var(--text-primary);
}

.chip--selected {
  background: rgba(88, 166, 255, 0.12);
  border-color: var(--accent-blue);
  color: var(--accent-blue);
}

/* ─── Command Palette ────────────────────────────────────────────────────────── */

.command-palette {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 500;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding-top: 80px;
  background: rgba(1, 4, 9, 0.75);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  animation: palette-fade-in 120ms ease;
}

@keyframes palette-fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

.command-palette-inner {
  width: 100%;
  max-width: 560px;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: 0 16px 48px rgba(0, 0, 0, 0.5);
  overflow: hidden;
  animation: palette-slide-in 150ms ease;
}

@keyframes palette-slide-in {
  from {
    opacity: 0;
    transform: translateY(-12px) scale(0.98);
  }
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

.command-palette-input {
  width: 100%;
  padding: 14px 16px;
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--border);
  color: var(--text-primary);
  font-family: var(--font-mono);
  font-size: 13px;
  outline: none;
  caret-color: var(--accent-blue);
}

.command-palette-input::placeholder {
  color: var(--text-primary);
  opacity: 0.5;
}

.command-palette-list {
  max-height: 360px;
  overflow-y: auto;
  padding: 4px 0;
}

.command-palette-empty {
  padding: 24px 16px;
  text-align: center;
  color: var(--text-muted);
  font-size: 12px;
}

.command-palette-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 14px;
  cursor: pointer;
  transition: background var(--transition);
  user-select: none;
}

.command-palette-item:hover,
.command-palette-item.selected {
  background: var(--bg-hover);
}

.command-palette-item.selected {
  background: var(--bg-hover);
}

.command-palette-item .palette-item-name {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-primary);
  flex-shrink: 0;
}

.command-palette-item .palette-item-desc {
  font-size: 11px;
  color: var(--text-muted);
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.command-palette-item .palette-item-group {
  flex-shrink: 0;
}

.command-palette-footer {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 14px;
  border-top: 1px solid var(--border);
  background: var(--bg-surface);
}

.palette-shortcut {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: 10px;
  color: var(--text-muted);
}

.palette-shortcut kbd {
  font-family: var(--font-mono);
  font-size: 10px;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 1px 5px;
  color: var(--text-secondary);
}

/* ─── Modal ──────────────────────────────────────────────────────────────────── */

#modal-overlay {
  position: fixed;
  inset: 0;
  /* Modals are always the topmost UI by convention — they're spawned from
     within other surfaces (top bar, onboarding step 3a facet picker,
     import/export, sidebar version popup, etc.) and must overlay whatever
     spawned them. Sits above #onboarding-overlay (410) and every lower
     layer (top bar 90/95/96, mobile-tab 96, slide-out 100, palette 1000
     which is the highest non-modal layer — kept below so command palette
     never traps focus from a modal it spawned). */
  z-index: 500;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(1, 4, 9, 0.75);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  animation: palette-fade-in 120ms ease;
}

#modal-overlay.hidden {
  display: none !important;
}

#modal-box {
  width: 100%;
  max-width: 480px;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 24px;
  box-shadow: 0 16px 48px rgba(0, 0, 0, 0.5);
  animation: palette-slide-in 150ms ease;
}

.modal-overlay {
  position: fixed;
  inset: 0;
  /* Class-form mirror of #modal-overlay above. Kept in sync — both layers
     must sit at 500 so modals stack above the onboarding overlay (410). */
  z-index: 500;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(1, 4, 9, 0.75);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}

.modal-box {
  width: 100%;
  max-width: 480px;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 24px;
  box-shadow: 0 16px 48px rgba(0, 0, 0, 0.5);
}

.modal-title {
  font-size: 15px;
  font-weight: var(--fw-semibold);
  color: var(--text-primary);
  margin-bottom: 12px;
}

.modal-body {
  font-size: 12px;
  color: var(--text-secondary);
  margin-bottom: 20px;
  line-height: 1.6;
}

.modal-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
}

/* ─── Visitor multi-voice (Phase 1) ────────────────────────────────────────
   "+ Add a voice" affordance + the modal list rows opened by
   components/visitor-add-voice.js. The visitor participant chip itself is
   the shared buildParticipantsCapsule helper — see conversations.js. */
.add-voice-button { height:28px; box-sizing:border-box; padding:0 12px; border-radius:14px; border:1px dashed var(--border); background:transparent; color:var(--text-secondary); font-size:13px; font-weight:var(--fw-medium); font-family:var(--font-ui); line-height:1.2; cursor:pointer; transition:color 120ms,border-color 120ms; flex-shrink:0; white-space:nowrap; }
.add-voice-button:hover { color:var(--accent-blue); border-color:var(--accent-blue); }
/* Dynamic label — three nested spans, CSS picks one per viewport width.
   Default: "+ Add member". ≤500px: "+ Add". ≤380px: "+". Keeps the button
   from clipping its sibling Delete on narrow mobile widths. */
.add-voice-button__label--short,
.add-voice-button__label--icon { display: none; }
@media (max-width: 500px) {
  .add-voice-button__label--full { display: none; }
  .add-voice-button__label--short { display: inline; }
  .add-voice-button { padding: 0 10px; }
}
@media (max-width: 380px) {
  .add-voice-button__label--short { display: none; }
  .add-voice-button__label--icon { display: inline; }
  .add-voice-button { padding: 0 8px; min-width: 28px; }
}
/* Smaller variant scoped to the discover sheet — keeps the conversations
   view's larger button untouched. */
.discover-overlay-panel .add-voice-button { height:22px; padding:0 9px; border-radius:11px; font-size:11.5px; }
.add-voice-list { display:grid; grid-template-columns:repeat(5, minmax(0, 1fr)); gap:14px 4px; max-height:60vh; overflow-y:auto; padding:2px; }
.add-voice-card { position:relative; padding:4px 2px; border:0; background:transparent; overflow:visible; cursor:pointer; display:flex; flex-direction:column; align-items:center; justify-content:flex-start; gap:6px; transition:transform 120ms, opacity 120ms; font-family:inherit; color:inherit; text-align:center; }
.add-voice-card:hover:not(:disabled):not(.is-added) .add-voice-card-avatar { transform:translateY(-1px); box-shadow:0 4px 14px color-mix(in srgb, var(--accent-blue) 24%, transparent); }
.add-voice-card:disabled { cursor:default; }
.add-voice-card.is-adding { opacity:0.55; pointer-events:none; }
.add-voice-card.is-added .add-voice-card-avatar { box-shadow:0 0 0 2px var(--accent-green); }
.add-voice-card-avatar { width:56px; height:56px; border-radius:50%; overflow:hidden; flex:none; transition:transform 120ms, box-shadow 120ms; }
.add-voice-card-name { width:100%; font-size:0.72rem; font-weight:var(--fw-semibold); color:var(--text-primary); line-height:1.15; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.add-voice-card-check { position:absolute; top:-2px; right:calc(50% - 32px); width:18px; height:18px; border-radius:50%; background:var(--accent-green); color:#fff; display:flex; align-items:center; justify-content:center; font-size:11px; font-weight:var(--fw-semibold); line-height:1; box-shadow:0 1px 3px rgba(0,0,0,0.25); pointer-events:none; border:2px solid var(--bg-elevated); }
.add-voice-card-error { position:absolute; inset:0; display:flex; align-items:center; justify-content:center; padding:8px; font-size:0.72rem; font-weight:var(--fw-semibold); color:#fff; background:color-mix(in srgb, var(--accent-red, #f85149) 80%, transparent); text-align:center; pointer-events:none; }
.add-voice-divider { grid-column:1 / -1; font-size:0.72rem; text-transform:uppercase; letter-spacing:0.06em; color:var(--text-muted); padding:10px 4px 4px; border-top:1px solid var(--border); margin-top:6px; }
@media (max-width: 480px) {
  .add-voice-list { grid-template-columns:repeat(4, minmax(0, 1fr)); }
}

/* ─── Onboarding overlay ──────────────────────────────────────────────────────
   Centered card overlay used for first-run + manual onboarding flow.
   Mounted lazily by components/onboarding.js the first time start() is
   called; toggled visible via the .open class. The card is medium-sized
   (~520px on desktop) and adapts to full-width minus gutters on mobile.
   z-index 410 sits above every base UI layer (top bar 90/95/96, slide-out
   100) but BELOW #modal-overlay (500). Modals spawned from within
   onboarding (e.g. Step 3a facet preview, error prompts) must overlay the
   onboarding overlay, not hide behind it. */
#onboarding-overlay {
  position: fixed;
  inset: 0;
  z-index: 410;
  display: none;
  align-items: center;
  justify-content: center;
  background: rgba(1, 4, 9, 0.55);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  padding: 16px;
  box-sizing: border-box;
}
#onboarding-overlay.open {
  display: flex;
  animation: palette-fade-in 140ms ease;
}

.onboarding-card {
  width: 100%;
  max-width: 520px;
  max-height: calc(100vh - 32px);
  display: flex;
  flex-direction: column;
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: 0 24px 64px rgba(0, 0, 0, 0.45);
  font-family: var(--font-ui);
  overflow: hidden;
  animation: palette-slide-in 160ms ease;
}

.onboarding-header {
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 18px 8px;
}
.onboarding-step-indicator {
  font-size: 0.74rem;
  color: var(--text-muted);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  flex-shrink: 0;
}
.onboarding-close {
  margin-left: auto;
  width: 28px;
  height: 28px;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: 50%;
  background: var(--bg-hover);
  color: var(--text-primary);
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: background 120ms, color 120ms, border-color 120ms;
}
.onboarding-close:hover {
  background: var(--bg-elevated);
  border-color: var(--text-muted);
}
/* Compact capsule indicator shown when onboarding is in demo mode. Lives in
   the header (absolutely centered) so it shares a row with the back button,
   step indicator, and close ✕. Stays out of the way while still flagging
   that nothing is being saved. */
.onb-demo-pill {
  background: color-mix(in srgb, var(--accent-blue) 14%, var(--bg-elevated));
  color: var(--accent-blue);
  border: 1px solid color-mix(in srgb, var(--accent-blue) 35%, transparent);
  border-radius: 999px;
  padding: 3px 10px;
  font-size: 0.7rem;
  font-weight: var(--fw-semibold);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  cursor: default;
  white-space: nowrap;
}
.onb-demo-pill--header {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  pointer-events: auto;
}

/* Leading-edge Back button in the header — circular always-visible chrome
   (the hover state is the default) so the affordance reads as a tappable
   target without needing a hover discovery pass. Pairs with the trailing
   ✕ close on the other edge. */
.onboarding-back {
  width: 28px;
  height: 28px;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: 50%;
  background: var(--bg-hover);
  color: var(--text-primary);
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: background 120ms, color 120ms, border-color 120ms;
}
.onboarding-back:hover {
  background: var(--bg-elevated);
  border-color: var(--text-muted);
}

.onboarding-progress {
  height: 3px;
  background: var(--border);
  margin: 0 18px;
  border-radius: 2px;
  overflow: hidden;
  flex-shrink: 0;
}
.onboarding-progress-fill {
  height: 100%;
  background: var(--accent-blue);
  transition: width 200ms ease;
}

.onboarding-body {
  padding: 28px 28px 20px;
  flex: 1;
  overflow-y: auto;
  min-height: 120px;
}
.onboarding-title {
  margin: 0 0 18px;
  font-size: 1.1rem;
  font-weight: var(--fw-semibold);
  color: var(--text-primary);
}
.onboarding-content {
  font-size: 0.9rem;
  color: var(--text-primary);
  line-height: 1.55;
}

.onboarding-footer {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 18px 28px 22px;
  border-top: 1px solid var(--border);
}
.onboarding-prev:disabled {
  opacity: 0.4;
  cursor: default;
}

@media (max-width: 767px) {
  .onboarding-card {
    max-width: 100%;
  }
}

/* ─── Tags ───────────────────────────────────────────────────────────────────── */

.tag {
  display: inline-flex;
  align-items: center;
  padding: 2px 8px;
  border-radius: var(--radius-sm);
  font-size: 10px;
  font-weight: var(--fw-medium);
  background: var(--bg-elevated);
  color: var(--text-secondary);
  border: 1px solid var(--border);
}

/* ─── Divider ────────────────────────────────────────────────────────────────── */

.divider {
  height: 1px;
  background: var(--border);
  margin: 12px 0;
  border: none;
}

/* ─── Loading ────────────────────────────────────────────────────────────────── */

.loading {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  color: var(--text-muted);
  font-size: 12px;
}

.loading::before {
  content: '';
  width: 14px;
  height: 14px;
  border: 2px solid var(--border);
  border-top-color: var(--accent-blue);
  border-radius: 50%;
  animation: spin 600ms linear infinite;
  flex-shrink: 0;
}

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

/* ─── Responsive: Sidebar Collapse ──────────────────────────────────────────── */

/* Mobile-only drawer affordances rendered by wiki.js renderLayout — hidden on
   desktop so the wiki view's 3-column layout stays byte-identical. The mobile
   @media block below switches them back on. */
#wiki-rail-toggle,
#wiki-rail-backdrop {
  display: none;
}

/* Mobile-only conversations drawer backdrop. Hidden on desktop. Inside the
   @media block below it becomes visible whenever the drawer is open
   (.conv-body is missing .conv-list-hidden) on mobile. */
#conv-list-backdrop { display: none; }

/* Wiki rail facet rows — kept indented (26px padding-left, set inline in
   components/wiki.js buildChatSidebar) so facets visually nest under Core.
   The tree-guide line + L-cap that previously drew a vertical hairline
   through the indent gutter was removed; the indent alone carries the
   parent/child relationship now. The .wiki-rail-facet-row /
   .wiki-rail-facet-row--last classes are still applied by buildChatSidebar
   in case we want to reintroduce the guide later, but no rules target them
   here. */

/* Desktop sidebar toggle — sits on the leading edge of per-mode panel
   headers (Identity title row, Wiki/Sources search bar) and toggles the
   chat rail's visibility. Mobile keeps the absolute-positioned
   #wiki-rail-toggle drawer hamburger that floats over the center panel,
   so this inline control hides on small viewports. Same chrome-stripped
   chevron treatment as `.conv-list-toggle` so all sidebar toggles read
   the same way across the app. */
.wiki-rail-collapse-btn {
  width: 28px;
  height: 28px;
  padding: 0 0 2px;
  box-sizing: border-box;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* Visible circular button — see .conv-list-toggle for the rationale. */
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 999px;
  color: var(--text-primary);
  font-size: 17px;
  font-weight: var(--fw-semibold);
  line-height: 1;
  cursor: pointer;
  flex-shrink: 0;
  transition: background 120ms, border-color 120ms;
}
.wiki-rail-collapse-btn:hover {
  background: var(--bg-hover);
  border-color: var(--text-muted);
}
/* Hides the chat rail when the desktop toggle is engaged.
   Scoped to desktop only: on mobile the rail is an off-canvas drawer
   governed by .mobile-rail-open, and renderLayout unconditionally adds
   .rail-collapsed when state.railCollapsedDesktop is true OR
   shouldHideFacetsRail() is true. Without this scope, a stale
   railCollapsedDesktop from a prior desktop session would leave the
   panel display:none on mobile and the hamburger toggle would be inert. */
@media (min-width: 768px) {
  #wiki-wrapper.rail-collapsed #wiki-left-panel {
    display: none !important;
  }
}

@media (max-width: 767px) {
  :root {
    --sidebar-width: 0px;
    /* Mobile-only bump: a slightly taller wiki/identity page header gives the
       title and hamburger more breathing room and matches the Conversations
       page header proportions on phone screens. */
    --page-header-mobile-height: 52px;
    /* Height of the mobile bottom tab bar (excluding safe-area inset). Used to
       reserve bottom padding on full-height views so chat composers / lists
       don't sit underneath the bar. */
    --bottom-tab-bar-height: 56px;
  }

  /* Use dynamic viewport height + iOS safe-area insets so the top bar isn't
     hidden behind the notch / dynamic island and the chat input isn't hidden
     behind the home-indicator or the Safari URL bar. */
  #app {
    height: 100dvh;
  }

  /* The left icon sidebar is replaced on mobile by the bottom tab bar below.
     `display: none !important` beats any inline `display:flex` left over from
     desktop layout. */
  #sidebar {
    display: none !important;
  }

  /* Mobile keeps the original 48px bar height — desktop bumped the var
     to 56px to fit the taller global search, but mobile shrinks the
     search input back to 30px so the original bar height still fits.
     --page-header-height drops to 48px on mobile to track --top-bar-height,
     keeping wiki inner headers flush with the sidebar/New Facet wrap.
     --nav-page-header-height stays at the same 40px the desktop slider uses;
     change here if the main-nav chrome should be taller on mobile. */
  :root {
    --top-bar-height: 48px;
    --page-header-height: 48px;
    --nav-page-header-height: 40px;
  }

  #top-bar {
    left: 0;
    /* Push the bar below the notch / status-bar safe area so the version
       badge and theme toggle aren't clipped on notched phones. */
    height: calc(var(--top-bar-height) + env(safe-area-inset-top));
    padding-top: env(safe-area-inset-top);
    padding-right: calc(16px + env(safe-area-inset-right));
  }

  #main-content {
    margin-left: 0;
    /* Match the taller top bar so views start below it. */
    padding-top: calc(var(--top-bar-height) + env(safe-area-inset-top));
    padding-right: env(safe-area-inset-right);
    /* Reserve room at the bottom for the fixed tab bar + iPhone home indicator
       so views (chat composer, lists, page bottoms) aren't hidden underneath. */
    padding-bottom: calc(var(--bottom-tab-bar-height) + env(safe-area-inset-bottom));
    /* Use dynamic viewport height — 100vh on iOS Safari includes the URL
       bar even when it's visible, eating ~60px off the bottom. */
    height: 100dvh;
  }

  /* Bottom tab bar — fixed to the bottom of the viewport, full width.
     z-index sits above the top bar (which is 90) and below the modal overlay. */
  #bottom-tab-bar {
    display: flex;
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 95;
    background: var(--bg-surface);
    border-top: 1px solid var(--border);
    padding-bottom: env(safe-area-inset-bottom);
    padding-left: env(safe-area-inset-left);
    padding-right: env(safe-area-inset-right);
    /* Subtle shadow so it visually floats above content scrolling underneath. */
    box-shadow: 0 -1px 4px rgba(0, 0, 0, 0.08);
    /* Horizontal scroll so adding more tabs (Identity + Wiki now share this
       row alongside Discover / Conversations / Facets / More) doesn't squeeze
       the existing ones below the touch-target floor. Each tab has a fixed
       min-width below; the bar scrolls when total width exceeds the viewport.
       overscroll-behavior:contain so a horizontal flick doesn't bleed up
       into the page's vertical scroll. */
    overflow-x: auto;
    overflow-y: hidden;
    overscroll-behavior-x: contain;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;            /* Firefox */
  }
  #bottom-tab-bar::-webkit-scrollbar { display: none; }  /* WebKit */

  .bottom-tab-bar-item {
    position: relative;
    /* Switched from `flex: 1` to a fixed min-width: with 6+ tabs in the row,
       flex:1 distributes shrinkage across all tabs and labels get clipped /
       buttons fall below the 44px touch-target floor. Fixed-width tabs +
       overflow-x:auto on the parent gives a predictable swipeable row. */
    flex: 0 0 auto;
    min-width: 80px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    min-height: 56px;
    padding: calc(6px + var(--nav-spacing-offset)) 4px;
    border: none;
    background: none;
    color: var(--text-primary);
    font-family: var(--font-ui);
    font-size: 14px;
    font-weight: var(--fw-medium);
    cursor: pointer;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
    transition: color var(--transition);
  }

  .bottom-tab-bar-item:active {
    background: var(--bg-hover);
  }

  /* Active state mirrors the sidebar's active-nav-item palette so the visual
     language is consistent across breakpoints. */
  .bottom-tab-bar-item.active {
    color: var(--text-primary);
    font-weight: var(--fw-bold);
  }

  /* Active-state indicator — small dot centered below the label, mirroring
     the desktop sidebar dot indicator and the facets sub-row dot pattern
     (buildSubRow in wiki.js) so the whole app uses one active-indicator
     language. Anchored to ::after on the label so it tracks the label
     center horizontally; the negative bottom offset pushes it into the
     button's bottom padding without crowding the text. The label normally
     has `overflow: hidden` (for text-overflow ellipsis) which would clip
     the ::after — override to `visible` on the active label since the
     bottom tab labels are short by design and don't need truncation. */
  .bottom-tab-bar-item.active .bottom-tab-bar-label {
    position: relative;
    overflow: visible;
  }
  .bottom-tab-bar-item.active .bottom-tab-bar-label::after {
    content: '';
    position: absolute;
    left: 50%;
    bottom: -16px;
    width: 5px;
    height: 5px;
    margin-left: -2.5px;
    background: var(--accent-blue);
    border-radius: 50%;
    pointer-events: none;
  }

  .bottom-tab-bar-icon {
    font-size: 20px;
    line-height: 1;
  }

  .bottom-tab-bar-label {
    font-size: 14px;
    line-height: 1.1;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 100%;
  }

  /* Overflow popover anchored to the ☰ "More" tab. The bottom tab bar lives
     at the screen bottom, so the menu opens upward from above the bar. The
     bar itself is z-index 95; this sits one above so it floats over content
     but still under the modal overlay. */
  .bottom-tab-more-menu {
    position: fixed;
    right: max(8px, env(safe-area-inset-right));
    bottom: calc(var(--bottom-tab-bar-height) + env(safe-area-inset-bottom) + 6px);
    z-index: 96;
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 6px;
    min-width: 180px;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.18);
  }

  .bottom-tab-more-menu.hidden {
    display: none;
  }

  .bottom-tab-more-option {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 12px;
    min-height: 44px;
    border: none;
    background: transparent;
    border-radius: var(--radius-sm);
    color: var(--text-primary);
    font-family: var(--font-ui);
    font-size: 15px;
    font-weight: var(--fw-medium);
    text-align: left;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
  }

  .bottom-tab-more-option:active {
    background: var(--bg-hover);
  }

  .bottom-tab-more-icon {
    font-size: 18px;
    line-height: 1;
    width: 20px;
    text-align: center;
  }

  .bottom-tab-more-label {
    line-height: 1.2;
  }

  .top-bar-team-name,
  #top-bar-leader {
    display: none;
  }

  /* Wiki chat panel — the inline styles in wiki.js set flex:1 on the list
     and put the footer at the end of a flex column. The remaining mobile
     issue is the composer's bottom padding sitting below the home-indicator;
     add a safe-area cushion that doesn't affect desktop. */
  #wiki-center-panel > div:last-child {
    padding-bottom: calc(12px + env(safe-area-inset-bottom));
  }

  /* Chat composer textarea + send button — bump font-size to 16px so iOS
     Safari doesn't auto-zoom the page when the input gets focus. (Anything
     below 16px triggers the zoom; once zoomed, the layout stops fitting.)
     Touch targets ≥44px on send. */
  #wiki-center-panel textarea {
    font-size: 16px !important;
    min-height: 44px !important;
  }
  /* Section-refine chat composer opts out of the 16px bump above so its
     size matches the canonical conversations msgTextarea (.composer-textarea
     at 0.85rem). Accept the iOS auto-zoom-on-focus tradeoff for visual parity. */
  #wiki-center-panel textarea.section-refine-composer {
    font-size: 0.85rem !important;
    min-height: var(--input-height) !important;
  }
  #wiki-center-panel .btn {
    min-height: 44px;
  }
  /* Small-capsule variants opt out of the 44px touch floor — they're
     explicitly sized for tighter chrome (edit-header Save button, etc.)
     and otherwise inflate to full-button height on mobile. */
  #wiki-center-panel .btn.btn-sm,
  #wiki-center-panel .btn.btn-xs {
    min-height: 0;
  }
  /* Section-refine action buttons (Send / Save → Preview / Cancel) opt OUT
     of both the wiki-wide 44px floor above and the .mm-chat-composer .btn
     stretch rule below. Specificity (id + 2 classes) wins over both;
     !important neutralizes the .mm-chat-composer !important downstream. */
  #wiki-center-panel .section-refine-actions .btn {
    min-height: 0 !important;
    align-self: auto !important;
  }
  /* Same opt-out for any pill-composer button (Send / Create / Save-to-Core
     etc.) inside the wiki center panel. These are the small-capsule action
     buttons nested inside a .pill-composer wrapper — sized to ~28px by the
     shared .pill-composer-action rule and meant to match the Conversations
     Send button regardless of which view they appear in. Without this the
     wiki-wide 44px floor stretches the wiki Create button (and the Core/
     facet chat Send) on mobile and breaks visual parity with the rest of
     the app's chat composers. */
  #wiki-center-panel .pill-composer-action {
    min-height: 0 !important;
  }
  /* Opt out: root-action chrome buttons (Backfill format hints, Wipe & Reset)
     sit in the Identity page-header on mobile and need to render at the same
     compact size as desktop. The 44px touch-target floor would balloon them
     and blow the 44px page-header row. */
  #wiki-center-panel .wiki-root-actions .btn {
    min-height: 0;
  }

  /* Chat sidebar (left wiki rail) on mobile: collapse to an off-canvas drawer.
     The wrapper (#wiki-wrapper) holds the rail + center; the rail is positioned
     absolutely and slid offscreen by default. A hamburger (#wiki-rail-toggle)
     and backdrop (#wiki-rail-backdrop) are rendered alongside; the wrapper
     gets .mobile-rail-open when the drawer is visible. Desktop is unaffected
     because all of these rules live inside this @media block. */
  #wiki-left-panel,
  :root[data-style~="liquid"] #wiki-wrapper #wiki-left-panel {
    width: 64vw !important;
    max-width: 256px;
    position: absolute !important;
    top: 0;
    left: 0;
    bottom: 0;
    z-index: 30;
    transform: translateX(-100%);
    transition: transform 220ms ease;
    box-shadow: 2px 0 12px rgba(0, 0, 0, 0.18);
    /* Force opaque surface on mobile — mirrors the .conv-list-col exception
       at line ~4661. On mobile this rail is an off-canvas drawer that overlays
       the center panel; the liquid translucent override (line ~4515) paints a
       55% translucent surface and the previous fix (commit 0863f50) couldn't
       beat it.

       Why this works where 0863f50 didn't: the previous attempt used
       `#wiki-left-panel` + !important (1 ID, specificity 100). The global
       liquid rule at line ~4515 is `:root[data-style~="liquid"] #wiki-left-panel`
       + !important (1 ID + 2 classes, specificity 120) AND comes later in
       source order — so it won on both counts. We now ALSO target the liquid
       form, but qualified with `#wiki-wrapper` ancestor (2 IDs + 2 classes,
       specificity 220) so it beats the global liquid rule on specificity
       even though it appears earlier in the file. */
    background: var(--bg-surface) !important;
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
  }
  /* Open state — slides the drawer in. Must match the specificity of the
     liquid-qualified off-canvas rule above (`:root[data-style~="liquid"]
     #wiki-wrapper #wiki-left-panel`, spec 220) or it'll lose to it under the
     default liquid theme and the panel will stay at translateX(-100%) even
     when .mobile-rail-open is set — backdrop fades in but no panel appears.
     Bare `#wiki-wrapper.mobile-rail-open #wiki-left-panel` alone is only
     spec 210 (2 IDs + 1 class), so we add a parallel liquid-prefixed selector
     that reaches spec 230 to win cleanly. Same dual-selector pattern used
     above for the off-canvas position rule. */
  #wiki-wrapper.mobile-rail-open #wiki-left-panel,
  :root[data-style~="liquid"] #wiki-wrapper.mobile-rail-open #wiki-left-panel {
    transform: translateX(0);
  }

  /* The facets list needs its OWN opaque container so the surface reads as a
     clear white card — matching the "New Facet" button row wrap above it,
     which paints `background:var(--bg-surface);border-bottom:1px solid var(--border)`
     inline in wiki.js buildChatSidebar (line ~1319). The list lives inside
     `.wiki-chat-sidebar` (the wrap that holds both the New Facet row AND the
     facet list), but the global liquid rule at line ~4522 sets
     `.wiki-chat-sidebar { background: transparent !important }` — so even
     after the rail panel is opaque (above), the list area visually merges
     with the center pane behind it. Painting --bg-surface explicitly here
     (with the same 2-ID specificity trick — `#wiki-wrapper #wiki-left-panel`
     ancestors — so we beat the global liquid `.wiki-chat-sidebar` rule)
     guarantees a single solid card-like surface from the New Facet row all
     the way down through the list. */
  #wiki-left-panel .wiki-chat-sidebar,
  :root[data-style~="liquid"] #wiki-wrapper #wiki-left-panel .wiki-chat-sidebar {
    background: var(--bg-surface) !important;
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
  }

  /* Mobile keeps the absolute-positioned drawer hamburger; hide the
     desktop in-panel toggle so we don't render two side-by-side
     toggles for the same surface. */
  .wiki-rail-collapse-btn {
    display: none;
  }

  /* Hamburger toggle — unified 28px capsule height matches the rest of the
     capsule control family (desktop .wiki-rail-collapse-btn is also 28×28).
     left:16px lines up with #top-bar's 16px gutter directly above. */
  #wiki-rail-toggle {
    position: absolute;
    /* Centered inside the 52px page header row: (52 − 28) / 2 = 12px. */
    top: 12px;
    left: 16px;
    z-index: 25;
    width: 28px;
    height: 28px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* Visible circular button — matches .conv-list-toggle and
       .wiki-rail-collapse-btn. `padding-bottom: 2px` optically centers
       `‹›` glyphs whose visual mass sits at x-height. */
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 999px;
    color: var(--text-primary);
    font-size: 17px;
    font-weight: var(--fw-semibold);
    line-height: 1;
    cursor: pointer;
    padding: 0 0 2px;
    box-sizing: border-box;
    transition: background 120ms, border-color 120ms;
  }
  #wiki-rail-toggle:hover {
    background: var(--bg-hover);
    border-color: var(--text-muted);
  }

  /* Make the hamburger float above center-panel content. All center-panel
     variants (chat, page-viewer, edit, identity) get an inner top spacer so
     the hamburger column (16px gutter + 32px width + 8px gap = 56px) is
     reserved on the left edge of any first-child header, keeping the search
     input / avatar / title from tucking under it. */
  #wiki-center-panel > div:first-child {
    padding-left: 56px !important;
  }
  /* Edit / Identity panels paint padding directly on #wiki-center-panel
     (no internal header), so push the top-edge content below the hamburger.
     Inline `padding:24px 32px` from wiki.js requires !important to override.
     Chat / page / identity opt out via data-mode — their header children
     share a 40px row with the hamburger, matching the Conversations /
     Discover / Facets page header height for cross-view parity. */
  #wiki-center-panel {
    padding-top: 40px !important;
  }
  #wiki-center-panel[data-mode] {
    padding-top: 0 !important;
  }
  /* Wiki page-header on mobile: forced to a single row inline with the
     hamburger toggle. Height pulled from --page-header-mobile-height (set
     in :root) so this stays in sync with the desktop header padding tokens.
     padding-left: 56px reserves the hamburger column (16px gutter + 32px
     toggle + 8px gap) so chrome aligns with the wiki menu bar; padding-right:
     16px matches that bar's trailing gutter. Search bar in page-viewer mode
     has `min-height:43px` inline so !important is required to shrink it down
     to the standard row. */
  #wiki-center-panel > .page-header,
  #wiki-center-panel[data-mode="page"] > div:first-child {
    min-height: var(--page-header-mobile-height) !important;
    max-height: var(--page-header-mobile-height) !important;
    padding-top: 4px !important;
    padding-bottom: 4px !important;
    padding-left: 56px !important;
    padding-right: 16px !important;
    box-sizing: border-box !important;
    overflow: hidden;
  }
  /* Wiki menu bar (Sources + page-viewer) — match the 44px page-header height
     used by Identity / Account / Help so all page title rows line up across
     views. Override the data-mode="page" clamp via the same selector
     specificity. */
  /* Specificity note: the rule above (`#wiki-center-panel > div:first-child`)
     uses :first-child which gives it (1,1,1). To win over its
     `padding-left: 44px !important`, add :first-child here too — that
     bumps this selector to (1,2,1) and lets the !important padding land. */
  #wiki-center-panel > .wiki-menu-bar:first-child,
  #wiki-center-panel[data-mode="page"] > .wiki-menu-bar:first-child {
    min-height: var(--page-header-mobile-height) !important;
    max-height: var(--page-header-mobile-height) !important;
    padding-top: 4px !important;
    padding-bottom: 4px !important;
    /* 16px gutter (matches #top-bar's `padding: 0 16px` so the wiki bar's
       left/right edges line up with the version capsule and other top-bar
       elements directly above) + 32px hamburger + 8px gap = 56px. */
    padding-left: 56px !important;
    padding-right: 16px !important;
    overflow: visible;
  }

  /* Backdrop — semi-transparent overlay covering everything except the rail.
     Hidden by default; only shown when drawer is open. */
  #wiki-rail-backdrop {
    display: none;
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(0, 0, 0, 0.45);
    z-index: 20;
  }
  #wiki-wrapper.mobile-rail-open #wiki-rail-backdrop {
    display: block;
  }

  /* Citations and long URLs in chat bubbles — prevent horizontal overflow
     that pushes the whole layout off-screen. */
  #wiki-center-panel,
  #wiki-center-panel * {
    overflow-wrap: anywhere;
    word-break: break-word;
  }

  /* Conversations list column on mobile: full off-canvas drawer pattern
     mirroring the wiki rail. The list is positioned absolutely and overlays
     the detail panel; the existing in-header chevron (.conv-list-toggle)
     stays in place and drives the open/close state. Default state on mobile
     is "closed" — conversations.js init() detects mobile and sets
     .conv-list-hidden on .conv-body so the user lands on the detail panel
     with the drawer hidden, exactly like facets.
     The override `display: flex !important` defeats the global
     `.conv-body.conv-list-hidden .conv-list-col { display: none !important }`
     rule so the drawer can animate via transform instead of snapping. */
  .conv-body { position: relative; }
  .conv-list-col {
    width: 64vw !important;
    max-width: 256px !important;
    position: absolute !important;
    top: 0;
    left: 0;
    bottom: 0;
    z-index: 30;
    transform: translateX(0);
    transition: transform 220ms ease;
    box-shadow: 2px 0 12px rgba(0, 0, 0, 0.18);
    background: var(--bg-surface);
    font-size: calc(15px * var(--conv-list-scale-mobile, 1));
  }
  .conv-body.conv-list-hidden .conv-list-col {
    display: flex !important;
    transform: translateX(-100%);
    pointer-events: none;
  }

  /* Backdrop — semi-transparent overlay covering the detail pane while the
     drawer is open. Visible only when .conv-list-hidden is absent (drawer
     open) on mobile. Tap closes the drawer. */
  #conv-list-backdrop {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(0, 0, 0, 0.45);
    z-index: 20;
  }
  .conv-body:not(.conv-list-hidden) #conv-list-backdrop {
    display: block;
  }

  /* Composer (textarea + Send button) — keep desktop sizing on mobile too
     (textarea ~38px, Send button ~30px). The previous 44px touch-target
     override was reverted in favor of visual parity with desktop. */

  /* Ensure all forms' inputs use 16px on mobile to prevent iOS zoom. */
  input[type="text"],
  input[type="email"],
  input[type="password"],
  input[type="search"],
  input[type="url"],
  textarea,
  select {
    font-size: 16px;
  }
}

/* ─── Account page ───────────────────────────────────────────────────────────── */

.account-page {
  max-width: 680px;
  padding: 28px 28px 40px;
  display: flex;
  flex-direction: column;
  gap: 24px;
}

.account-panel {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  overflow: hidden;
}

.account-panel--danger {
  border-color: rgba(248, 81, 73, 0.35);
}

.account-panel-title {
  font-size: 12px;
  font-weight: var(--fw-semibold);
  color: var(--text-secondary);
  padding: 12px 16px;
  border-bottom: 1px solid var(--border);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.account-panel-title--danger {
  color: var(--accent-red);
}

.account-panel-body {
  padding: 16px;
}

.account-panel-desc {
  font-size: 12px;
  color: var(--text-secondary);
  margin-bottom: 14px;
}

/* Profile grid */
.account-profile-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px 24px;
}

.account-field {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.account-field-label {
  font-size: 10px;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.account-field-value {
  font-size: 12px;
  color: var(--text-primary);
  font-family: var(--font-ui);
}

/* Status grid */
.account-status-grid {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.account-status-row {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 12px;
}

.account-status-row--meta {
  color: var(--text-secondary);
  margin-top: 4px;
}

.account-status-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
}

.account-status-dot--green  { background: var(--accent-green); }
.account-status-dot--amber  { background: var(--accent-orange); }

.account-status-label {
  color: var(--text-secondary);
  min-width: 130px;
}

.account-status-value {
  color: var(--text-primary);
}

/* Danger zone */
.account-danger-row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 20px;
  padding: 12px 0;
  border-bottom: 1px solid var(--border);
}

.account-danger-row:last-child {
  border-bottom: none;
  padding-bottom: 0;
}

.account-danger-row--muted {
  opacity: 0.5;
}

.account-danger-info {
  flex: 1;
  min-width: 0;
}

.account-danger-info strong {
  display: block;
  font-size: 12px;
  color: var(--text-primary);
  margin-bottom: 4px;
}

.account-danger-info p {
  font-size: 11px;
  color: var(--text-secondary);
  line-height: 1.6;
}

/* Shared states */
.account-loading {
  font-size: 12px;
  color: var(--text-muted);
}

.account-error {
  font-size: 12px;
  color: var(--accent-red);
}

.account-output {
  background: var(--bg-base);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 10px;
  font-size: 11px;
  font-family: var(--font-mono);
  color: var(--text-primary);
  white-space: pre-wrap;
  max-height: 240px;
  overflow-y: auto;
  margin: 0;
}

/* ─── Import / Export page ───────────────────────────────────────────────────── */

.ie-page {
  max-width: 760px;
  padding: 28px 28px 40px;
  display: flex;
  flex-direction: column;
  gap: 24px;
}

.ie-panel {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  overflow: hidden;
}

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

.ie-panel-title {
  font-size: 12px;
  font-weight: var(--fw-semibold);
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.ie-panel-body {
  padding: 16px;
}

.ie-panel-desc {
  font-size: 12px;
  color: var(--text-secondary);
  margin-bottom: 14px;
}

/* Bundles table */
.ie-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 12px;
}

.ie-table th {
  text-align: left;
  padding: 6px 10px;
  font-size: 10px;
  font-weight: var(--fw-semibold);
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  border-bottom: 1px solid var(--border);
}

.ie-table td {
  padding: 8px 10px;
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
}

.ie-table tr:last-child td {
  border-bottom: none;
}

.ie-table tr:hover td {
  background: var(--bg-hover);
}

.ie-cell-name {
  font-family: var(--font-ui);
  color: var(--text-primary);
  max-width: 200px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.ie-cell-date {
  color: var(--text-secondary);
  white-space: nowrap;
}

.ie-cell-size {
  color: var(--text-muted);
  white-space: nowrap;
}

.ie-cell-actions {
  display: flex;
  gap: 4px;
  justify-content: flex-end;
  white-space: nowrap;
}

/* Row highlight (post-reset) */
@keyframes ie-row-highlight {
  0%   { background: rgba(88, 166, 255, 0.18); }
  100% { background: transparent; }
}

.ie-row--highlight td {
  animation: ie-row-highlight 3s ease-out forwards;
}

/* Import from file */
.ie-import-row {
  display: flex;
  align-items: center;
  gap: 10px;
}

.ie-file-input {
  flex: 1;
  font-size: 12px;
  color: var(--text-secondary);
  font-family: var(--font-ui);
}

/* Shared states */
.ie-loading {
  font-size: 12px;
  color: var(--text-muted);
}

.ie-empty {
  font-size: 12px;
  color: var(--text-secondary);
  padding: 8px 0;
}

.ie-error {
  font-size: 12px;
  color: var(--accent-red);
}

.ie-output {
  background: var(--bg-base);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 10px;
  font-size: 11px;
  font-family: var(--font-mono);
  color: var(--text-primary);
  white-space: pre-wrap;
  max-height: 240px;
  overflow-y: auto;
  margin: 0;
}

/* === bundle shares === */

/* Per-row "Shares (n)" badge; rendered as a clickable button styled like a pill */
.bs-shares-badge {
  background: rgba(63, 185, 80, 0.12);
  color: var(--accent-green);
  border: 1px solid rgba(63, 185, 80, 0.25);
  cursor: pointer;
  font: inherit;
  padding: 2px 7px;
  border-radius: var(--radius-pill);
  font-size: 10px;
  font-weight: var(--fw-medium);
  font-family: var(--font-ui);
  margin-left: 4px;
}
.bs-shares-badge:hover {
  background: rgba(63, 185, 80, 0.22);
}

/* Share status pill — slightly tighter to fit alongside other content */
.bs-status-pill {
  margin-left: 6px;
}

/* Create-share modal form */
.bs-share-form {
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.bs-share-intro {
  margin: 0;
  font-size: 12px;
  color: var(--text-secondary);
  line-height: 1.5;
}
.bs-field-group {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.bs-field-label {
  font-size: 10px;
  font-weight: var(--fw-semibold);
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.bs-radio-row {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 16px;
}
.bs-radio {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: var(--text-primary);
  font-family: var(--font-ui);
  cursor: pointer;
  user-select: none;
}
.bs-radio input[type="radio"] {
  cursor: pointer;
}
.bs-error {
  font-size: 11px;
  color: var(--accent-red);
  background: rgba(248, 81, 73, 0.08);
  border: 1px solid rgba(248, 81, 73, 0.25);
  border-radius: var(--radius-sm);
  padding: 8px 10px;
}

/* Success / copy-link UI */
.bs-success-intro {
  margin: 0 0 10px 0;
  font-size: 12px;
  color: var(--text-primary);
}
.bs-link-row {
  display: flex;
  align-items: center;
  gap: 8px;
}
.bs-link-input {
  flex: 1;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-primary);
  background: var(--bg-base);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 8px 10px;
  min-width: 0;
}
.bs-meta {
  margin-top: 12px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 11px;
  color: var(--text-secondary);
}
.bs-token-line code {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-muted);
}
.bs-copy-status {
  margin-top: 8px;
  font-size: 11px;
  color: var(--accent-green);
}

/* Shares list modal */
.bs-shares-list-wrap {
  min-width: 320px;
}
.bs-shares-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.bs-share-row {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 10px 12px;
  background: var(--bg-base);
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.bs-share-row--inactive {
  opacity: 0.6;
}
.bs-share-row-main {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.bs-share-token {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--text-primary);
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 1px 6px;
}
.bs-share-uses {
  font-size: 11px;
  color: var(--text-secondary);
  margin-left: auto;
}
.bs-share-row-meta {
  font-size: 10px;
  color: var(--text-muted);
}
.bs-share-row-actions {
  display: flex;
  gap: 6px;
  justify-content: flex-end;
  margin-top: 4px;
}

/* === /bundle shares === */

/* === billing === */
.billing-balance-row {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 4px 0 12px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 16px;
}
.billing-balance-label {
  font-size: 12px;
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.billing-balance-value {
  font-size: 28px;
  font-weight: var(--fw-semibold);
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}
.billing-balance-unit {
  font-size: 13px;
  color: var(--text-secondary);
}
.billing-refresh-btn {
  margin-left: auto;
}

.billing-frozen-banner {
  background: rgba(248, 81, 73, 0.08);
  border: 1px solid rgba(248, 81, 73, 0.35);
  color: var(--accent-red);
  border-radius: var(--radius-md);
  padding: 10px 14px;
  margin-bottom: 16px;
  font-size: 13px;
  line-height: 1.5;
}
.billing-frozen-banner strong {
  margin-right: 6px;
}

.billing-section {
  margin-bottom: 18px;
}
.billing-section:last-child {
  margin-bottom: 0;
}
.billing-section-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 8px;
}
.billing-section-title {
  font-size: 12px;
  font-weight: var(--fw-semibold);
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin: 0 0 8px 0;
}
.billing-section-header .billing-section-title {
  margin-bottom: 0;
}

.billing-card-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
}
@media (max-width: 720px) {
  .billing-card-grid {
    grid-template-columns: 1fr;
  }
}

.billing-card {
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 14px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
}
.billing-card-name {
  font-size: 13px;
  font-weight: var(--fw-semibold);
  color: var(--text-primary);
}
.billing-card-price {
  font-size: 22px;
  font-weight: var(--fw-semibold);
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}
.billing-card-period {
  font-size: 13px;
  font-weight: var(--fw-regular);
  color: var(--text-secondary);
  margin-left: 2px;
}
.billing-card-tokens {
  font-size: 12px;
  color: var(--text-secondary);
}
.billing-buy-btn {
  margin-top: 6px;
  align-self: stretch;
}
.billing-card-error {
  font-size: 12px;
  color: var(--accent-red);
  margin-top: 4px;
  word-break: break-word;
}

.billing-empty {
  font-size: 13px;
  color: var(--text-muted);
  padding: 8px 0;
}

.billing-history {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.billing-history-row {
  display: grid;
  grid-template-columns: minmax(140px, 1.4fr) 64px 1fr auto;
  align-items: center;
  gap: 10px;
  padding: 6px 8px;
  border-radius: var(--radius-sm);
  font-size: 12px;
}
.billing-history-row:nth-child(odd) {
  background: var(--bg-surface);
}
.billing-history-date {
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
}
.billing-history-type {
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-size: 10px;
}
.billing-history-label {
  color: var(--text-primary);
}
.billing-history-tag {
  display: inline-block;
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-muted);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 0 4px;
  margin-left: 4px;
}
.billing-history-amt {
  font-variant-numeric: tabular-nums;
  font-weight: var(--fw-semibold);
  text-align: right;
}
.billing-history-amt--pos {
  color: var(--accent-green);
}
.billing-history-amt--neg {
  color: var(--accent-red);
}
.billing-history-amt--neutral {
  color: var(--text-muted);
}
/* === /billing === */

/* ─── Identity grouped sections (SwiftUI Form-style cards) ──────────────────── */

.identity-section-card {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 0;
  margin-bottom: 10px;
  overflow: hidden;
}
.identity-section-card > h3.identity-section-header {
  font-size: 0.8125rem;
  font-weight: var(--fw-semibold);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-primary);
  margin: 0;
  padding: 12px 18px;
  border-bottom: 1px solid var(--border);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: space-between;
  user-select: none;
  transition: background 120ms;
}
.identity-section-card > h3.identity-section-header:hover {
  background: var(--bg-hover);
}
.identity-section-card.collapsed > h3.identity-section-header {
  border-bottom: none;
}
.identity-section-title {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.identity-section-trailing {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  flex-shrink: 0;
  text-transform: none;
  letter-spacing: 0;
  font-weight: var(--fw-regular);
}
.identity-section-status {
  font-size: 0.8125rem;
  color: var(--text-primary);
  opacity: 0.7;
  font-family: var(--font-ui);
}
.identity-section-status--empty {
  font-style: italic;
}
.identity-section-chev {
  color: var(--text-muted);
  font-size: 0.85em;
  flex-shrink: 0;
  /* Single ⌃ glyph rotated by parent state — keeps stroke weight identical
     across orientations. Default (expanded) points down; .collapsed → right. */
  display: inline-block;
  transition: transform 120ms ease;
  transform: rotate(180deg);
}
.identity-section-card.collapsed .identity-section-chev {
  transform: rotate(90deg);
}
.identity-section-body {
  padding: 12px 18px 14px;
}
.identity-section-card.collapsed > .identity-section-body {
  display: none;
}
.identity-section-body > p,
.identity-section-body > li {
  margin: 4px 0;
}
/* Wiki markdown lists — the renderer wraps consecutive `- ` / `* ` lines in
   <ul class="wiki-ul">. Give it real left padding so bullets are visible
   and the text aligns nicely under the section content. */
.wiki-ul {
  list-style: disc outside;
  padding-left: 1.4em;
  margin: 4px 0;
}
.wiki-ul > .wiki-li {
  margin: 2px 0;
}
.identity-section-body > br:first-child,
.identity-section-body > br + br {
  display: none;
}

/* ─── Help View ──────────────────────────────────────────────────────────────── */

.help-view {
  padding: 24px;
  max-width: 760px;
}

.help-toc {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 24px;
  padding: 12px 16px;
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: 8px;
}

.help-toc-link {
  font-size: 13px;
  color: var(--text-secondary);
  text-decoration: none;
  padding: 4px 10px;
  border-radius: 4px;
  transition: background 0.15s, color 0.15s;
}

.help-toc-link:hover {
  background: var(--bg-base);
  color: var(--text-primary);
}

.help-section {
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 24px;
  margin-bottom: 20px;
  scroll-margin-top: 16px;
}

.help-section-title {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin: 0 0 16px;
}

.help-section-body {
  color: var(--text-primary);
  font-size: 14px;
  line-height: 1.65;
}

.help-section-body h4 {
  font-size: 14px;
  font-weight: 600;
  color: var(--text-primary);
  margin: 20px 0 8px;
}

.help-section-body h4:first-child {
  margin-top: 0;
}

.help-section-body p {
  margin: 0 0 12px;
}

.help-section-body ul,
.help-section-body ol {
  margin: 0 0 12px;
  padding-left: 22px;
}

.help-section-body li {
  margin-bottom: 6px;
}

.help-section-body strong {
  color: var(--text-primary);
  font-weight: 600;
}

.help-section-body em {
  color: var(--text-secondary);
  font-style: italic;
}

/* ── Help disclosure groups ───────────────────────────────────────────────
   Each topic inside a help section is a native <details> element with a
   custom summary. Multi-open by default — independent state per group. */
.help-disclosure {
  background: var(--bg-base);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  margin-bottom: 10px;
  overflow: hidden;
  transition: border-color 0.15s;
}

.help-disclosure:last-child {
  margin-bottom: 0;
}

.help-disclosure:hover {
  border-color: var(--text-muted);
}

.help-disclosure[open] {
  border-color: var(--accent-blue);
}

.help-disclosure > summary {
  list-style: none;
  cursor: pointer;
  padding: 12px 16px;
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 14px;
  font-weight: 600;
  color: var(--text-primary);
  user-select: none;
}

.help-disclosure > summary::-webkit-details-marker {
  display: none;
}

.help-disclosure-body {
  padding: 0 16px 14px 38px;
  font-size: 14px;
  line-height: 1.65;
  color: var(--text-primary);
}

.help-disclosure-body p {
  margin: 0 0 12px;
}

.help-disclosure-body p:last-child {
  margin-bottom: 0;
}

.help-disclosure-body ul,
.help-disclosure-body ol {
  margin: 0 0 12px;
  padding-left: 22px;
}

.help-disclosure-body li {
  margin-bottom: 6px;
}

.help-disclosure-body strong {
  color: var(--text-primary);
  font-weight: 600;
}

.help-disclosure-body em {
  color: var(--text-secondary);
  font-style: italic;
}


/* ─── Liquid / Glass ───────────────────────────────────────────────────────────
   Internal codename "Hush". One material, one light source, one accent. Uses
   the app's own palette — shades of --accent-blue and the neutral surface
   variables — so it reads as the same product, not a different one. Both
   modes share a single ruleset because the variables already swap.
   Scoped to #view-help and #view-discover (and discover-overlay) only.

   Selector note: rules below use [data-style~="liquid"] (token list) so that
   either `data-style="liquid"` (Liquid) or `data-style="liquid glass"` (Glass)
   matches. The Glass surface style is the Liquid surface PLUS a specular edge
   glare on circles and capsules — those glare rules use [data-style~="glass"]
   and live at the bottom of this file. */

:root[data-style~="liquid"] #view-help {
  background-color: var(--bg-base);
  background-image:
    radial-gradient(120% 60% at 50% -20%,
      color-mix(in srgb, var(--accent-blue) 12%, transparent) 0%,
      color-mix(in srgb, var(--accent-blue) 5%, transparent) 38%,
      transparent 72%),
    linear-gradient(180deg,
      transparent 78%,
      color-mix(in srgb, var(--accent-blue) 4%, transparent) 100%);
  background-attachment: fixed;
  background-repeat: no-repeat;
  background-size: cover;
}

/* TOC — quiet links over a hairline tinted with the accent. No strip. */
:root[data-style~="liquid"] .help-toc {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin: 0 0 28px;
  padding: 0 0 14px;
  background: transparent;
  border: 0;
  border-bottom: 1px solid color-mix(in srgb, var(--accent-blue) 18%, var(--border));
  border-radius: 0;
  box-shadow: none;
}

:root[data-style~="liquid"] .help-toc-link {
  padding: 6px 10px;
  font-size: 13px;
  font-weight: 500;
  color: var(--text-secondary);
  background: transparent;
  border: 0;
  border-radius: 6px;
  text-decoration: none;
  transition: color 200ms ease;
}

:root[data-style~="liquid"] .help-toc-link:hover {
  color: var(--accent-blue);
  background: transparent;
}

/* Section — one card, one blur, one hairline. Generous interior. */
:root[data-style~="liquid"] .help-section {
  margin: 0 0 24px;
  padding: 32px;
  border-radius: 20px;
  background: color-mix(in srgb, var(--bg-card) 55%, transparent);
  backdrop-filter: blur(20px) saturate(160%);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
  border: 1px solid color-mix(in srgb, var(--accent-blue) 10%, var(--border));
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, var(--text-primary) 6%, transparent),
    0 18px 50px -24px color-mix(in srgb, var(--bg-base) 60%, black);
}

/* Title — normal weight, no caps, no tracking. A label, not a poster. */
:root[data-style~="liquid"] .help-section-title {
  margin: 0 0 22px;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  color: var(--text-muted);
}

/* Body — larger, looser leading. Let it breathe. */
:root[data-style~="liquid"] .help-section-body {
  font-size: 15px;
  line-height: 1.7;
  color: var(--text-primary);
}

/* Disclosure — no border, no card. A soft capsule pill in the leading gutter
   mirrors .conv-list-item::before and .sidebar-nav-item.active so the whole
   app speaks one active-indicator language. */
:root[data-style~="liquid"] .help-disclosure {
  position: relative;
  margin: 0 0 4px;
  padding: 0;
  background: transparent;
  border: 0;
  border-radius: 10px;
  box-shadow: none;
  overflow: hidden;
  transition: background-color 240ms ease;
}

:root[data-style~="liquid"] .help-disclosure::before {
  /* Capsule indicator on the leading edge. 6px top/bottom inset leaves a
     small breathing margin while filling nearly the full vertical span of
     both closed (~46px) and open (~300px+) cards. Previous 18% percentage
     inset shrank the capsule too much on the closed state. */
  content: '';
  position: absolute;
  left: 6px;
  top: 6px;
  bottom: 6px;
  width: 3px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--accent-blue) 22%, transparent);
  transition: background-color 240ms ease;
  pointer-events: none;
}

:root[data-style~="liquid"] .help-disclosure[open] {
  background: color-mix(in srgb, var(--accent-blue) 6%, transparent);
}

:root[data-style~="liquid"] .help-disclosure[open]::before {
  background: var(--accent-blue);
}

:root[data-style~="liquid"] .help-disclosure > summary {
  list-style: none;
  cursor: pointer;
  padding: 12px 16px 12px 20px;
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: 15px;
  font-weight: 500;
  color: var(--text-primary);
  transition: padding 220ms cubic-bezier(0.4, 0, 0.2, 1);
}

/* Open — the card grows taller with breathing room above + below so the
   content sits inset from the tinted background's top/bottom edges. */
:root[data-style~="liquid"] .help-disclosure[open] > summary {
  padding-top: 18px;
  padding-bottom: 18px;
}

:root[data-style~="liquid"] .help-disclosure > summary::-webkit-details-marker {
  display: none;
}

:root[data-style~="liquid"] .help-disclosure-body {
  padding: 4px 16px 20px 30px;
  font-size: 14.5px;
  line-height: 1.68;
  color: var(--text-secondary);
}

/* ── Discover view ─────────────────────────────────────────────────────────── */

:root[data-style~="liquid"] #view-discover {
  background-color: var(--bg-base);
  background-image:
    radial-gradient(120% 60% at 50% -20%,
      color-mix(in srgb, var(--accent-blue) 12%, transparent) 0%,
      color-mix(in srgb, var(--accent-blue) 5%, transparent) 38%,
      transparent 72%),
    linear-gradient(180deg,
      transparent 78%,
      color-mix(in srgb, var(--accent-blue) 4%, transparent) 100%);
  background-attachment: fixed;
  background-repeat: no-repeat;
  background-size: cover;
}

/* Toolbar — translucent over the ambient, hairline rule beneath. The
   default rule already sets sticky+z-index; we only retint surfaces. */
:root[data-style~="liquid"] .discover-toolbar {
  background: color-mix(in srgb, var(--bg-base) 55%, transparent);
  backdrop-filter: blur(20px) saturate(160%);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
  border-bottom-color: color-mix(in srgb, var(--accent-blue) 14%, var(--border));
}

:root[data-style~="liquid"] .discover-toolbar-search,
:root[data-style~="liquid"] .discover-toolbar-sort {
  background: color-mix(in srgb, var(--bg-surface) 50%, transparent);
  border-color: color-mix(in srgb, var(--accent-blue) 12%, var(--border));
}

:root[data-style~="liquid"] .discover-toolbar-search:focus,
:root[data-style~="liquid"] .discover-toolbar-sort:focus {
  border-color: var(--accent-blue);
}

/* Cards — same translucent card recipe as .help-section. Override the inline
   `border-left: 3px solid ${facet.color}` from discover-card.js with
   !important so the colored peek doesn't bleed through under glass. */
:root[data-style~="liquid"] .discover-card {
  background: color-mix(in srgb, var(--bg-card) 55%, transparent);
  backdrop-filter: blur(20px) saturate(160%);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
  border: 1px solid color-mix(in srgb, var(--accent-blue) 10%, var(--border)) !important;
  border-radius: 16px;
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, var(--text-primary) 5%, transparent),
    0 12px 32px -20px color-mix(in srgb, var(--bg-base) 60%, black);
}

:root[data-style~="liquid"] .discover-card:hover {
  border-color: color-mix(in srgb, var(--accent-blue) 24%, var(--border)) !important;
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, var(--text-primary) 6%, transparent),
    0 18px 40px -22px color-mix(in srgb, var(--bg-base) 50%, black);
}

/* Chips — translucent pill with a faint accent tint. */
:root[data-style~="liquid"] .discover-chip {
  background: color-mix(in srgb, var(--bg-elevated) 50%, transparent);
  border-color: color-mix(in srgb, var(--accent-blue) 14%, var(--border));
}

/* Overlay — discover-overlay.js sets the panel/backdrop styles inline via
   element.style.cssText, so we need !important to win. The facet-color
   left border (panel.style.borderLeft) is left untouched: we override
   top/right/bottom individually, not the shorthand. */
:root[data-style~="liquid"] .discover-overlay {
  background: color-mix(in srgb, var(--bg-base) 50%, transparent) !important;
  backdrop-filter: blur(12px) saturate(160%) !important;
  -webkit-backdrop-filter: blur(12px) saturate(160%) !important;
}

:root[data-style~="liquid"] .discover-overlay-panel {
  background: color-mix(in srgb, var(--bg-card) 55%, transparent) !important;
  backdrop-filter: blur(28px) saturate(180%) !important;
  -webkit-backdrop-filter: blur(28px) saturate(180%) !important;
  border: 1px solid color-mix(in srgb, var(--accent-blue) 12%, var(--border)) !important;
  border-radius: 20px !important;
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, var(--text-primary) 6%, transparent),
    0 18px 50px -24px color-mix(in srgb, var(--bg-base) 60%, black) !important;
}

:root[data-style~="liquid"] .discover-overlay-header {
  border-bottom-color: color-mix(in srgb, var(--accent-blue) 14%, var(--border)) !important;
}

:root[data-style~="liquid"] .discover-overlay-prompt {
  background: color-mix(in srgb, var(--bg-elevated) 45%, transparent);
  border-color: color-mix(in srgb, var(--accent-blue) 12%, var(--border));
}

:root[data-style~="liquid"] .discover-overlay-prompt:hover {
  background: color-mix(in srgb, var(--bg-hover) 55%, transparent);
  border-color: var(--accent-blue);
}

/* ── Wiki view (sidebar "Facets" routes here in cloud) ─────────────────────── */

:root[data-style~="liquid"] #view-wiki {
  background-color: var(--bg-base);
  background-image:
    radial-gradient(120% 60% at 50% -20%,
      color-mix(in srgb, var(--accent-blue) 12%, transparent) 0%,
      color-mix(in srgb, var(--accent-blue) 5%, transparent) 38%,
      transparent 72%),
    linear-gradient(180deg,
      transparent 78%,
      color-mix(in srgb, var(--accent-blue) 4%, transparent) 100%);
  background-attachment: fixed;
  background-repeat: no-repeat;
  background-size: cover;
}

/* Left rail — translucent strip with accent-tinted right hairline. The inline
   style.cssText on #wiki-left-panel sets background + border-right, so both
   need !important to win. */
:root[data-style~="liquid"] #wiki-left-panel {
  background: color-mix(in srgb, var(--bg-surface) 55%, transparent) !important;
  backdrop-filter: blur(20px) saturate(160%);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
  border-right: 1px solid color-mix(in srgb, var(--accent-blue) 14%, var(--border)) !important;
}

:root[data-style~="liquid"] .wiki-chat-sidebar {
  background: transparent !important;
  border-bottom: 1px solid color-mix(in srgb, var(--accent-blue) 14%, var(--border)) !important;
}

/* Rail rows — the default dot/capsule indicator (buildSubRow in wiki.js
   and .sidebar-nav-item.active::before) already does its job, so glass
   leaves the rows untouched. Just the panel surface and toolbar get
   retinted above. */

:root[data-style~="liquid"] #view-wiki > .page-header,
:root[data-style~="liquid"] .wiki-menu-bar {
  background: color-mix(in srgb, var(--bg-base) 55%, transparent);
  backdrop-filter: blur(20px) saturate(160%);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
  border-bottom: 1px solid color-mix(in srgb, var(--accent-blue) 14%, var(--border));
}

:root[data-style~="liquid"] .identity-section-card {
  background: color-mix(in srgb, var(--bg-card) 55%, transparent);
  backdrop-filter: blur(20px) saturate(160%);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
  border: 1px solid color-mix(in srgb, var(--accent-blue) 10%, var(--border));
  border-radius: 16px;
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, var(--text-primary) 5%, transparent),
    0 12px 32px -20px color-mix(in srgb, var(--bg-base) 60%, black);
}

:root[data-style~="liquid"] .identity-section-card > h3.identity-section-header {
  background: transparent;
  border-bottom-color: color-mix(in srgb, var(--accent-blue) 14%, var(--border));
  text-transform: none;
  letter-spacing: 0;
  font-weight: 500;
  color: var(--text-primary);
}

:root[data-style~="liquid"] .identity-section-card.collapsed > h3.identity-section-header {
  border-bottom: 0;
}

:root[data-style~="liquid"] .identity-section-card > h3.identity-section-header:hover {
  background: color-mix(in srgb, var(--accent-blue) 5%, transparent);
}

:root[data-style~="liquid"] .wiki-content {
  font-size: 15px;
  line-height: 1.72;
  color: var(--text-primary);
}

:root[data-style~="liquid"] .wiki-link {
  color: var(--accent-blue);
  text-decoration: none;
  border-bottom: 1px solid color-mix(in srgb, var(--accent-blue) 30%, transparent);
}

:root[data-style~="liquid"] .wiki-link:hover {
  border-bottom-color: var(--accent-blue);
}

:root[data-style~="liquid"] .wiki-inline-code,
:root[data-style~="liquid"] .wiki-code-block {
  background: color-mix(in srgb, var(--bg-elevated) 50%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent-blue) 10%, var(--border));
  border-radius: 8px;
}

:root[data-style~="liquid"] #wiki-center-panel .pill-composer,
:root[data-style~="liquid"] #wiki-center-panel .input,
:root[data-style~="liquid"] #wiki-center-panel textarea,
:root[data-style~="liquid"] #wiki-center-panel select {
  background: color-mix(in srgb, var(--bg-surface) 50%, transparent);
  border-color: color-mix(in srgb, var(--accent-blue) 12%, var(--border));
}

/* Strip the Liquid translucent fill from inputs nested inside a
   pill-composer. Without this, the textarea/input got its own 50%
   surface fill on top of the pill's identical 50% fill — two stacked
   translucent layers compound to a brighter inner rectangle with a
   hairline-sharp edge where they meet. The pill carries the only fill;
   the nested control stays transparent so it reads as a single layer. */
:root[data-style~="liquid"] #wiki-center-panel .pill-composer > textarea,
:root[data-style~="liquid"] #wiki-center-panel .pill-composer > input,
:root[data-style~="liquid"] #wiki-center-panel .pill-composer > .composer-textarea,
:root[data-style~="liquid"] #wiki-center-panel .pill-composer > .input,
:root[data-style~="liquid"] #wiki-center-panel .pill-composer > .textarea {
  background: transparent;
}

:root[data-style~="liquid"] #wiki-center-panel .pill-composer:focus-within,
:root[data-style~="liquid"] #wiki-center-panel .input:focus,
:root[data-style~="liquid"] #wiki-center-panel textarea:focus,
:root[data-style~="liquid"] #wiki-center-panel select:focus {
  border-color: var(--accent-blue);
}

:root[data-style~="liquid"] #wiki-rail-toggle,
:root[data-style~="liquid"] .wiki-rail-collapse-btn {
  /* Bumped from 55% → 82% so the circle reads on glass panels in both
     light and dark themes. Border strengthened to a solid hairline with
     an accent tint so the edge is visible against the blurred surface. */
  background: color-mix(in srgb, var(--bg-card) 82%, transparent);
  backdrop-filter: blur(14px) saturate(160%);
  -webkit-backdrop-filter: blur(14px) saturate(160%);
  border: 1px solid color-mix(in srgb, var(--accent-blue) 28%, var(--border));
}

:root[data-style~="liquid"] #wiki-rail-toggle:hover,
:root[data-style~="liquid"] .wiki-rail-collapse-btn:hover {
  background: color-mix(in srgb, var(--bg-card) 92%, transparent);
  border-color: var(--accent-blue);
}

/* ── Conversations view ────────────────────────────────────────────────────── */

:root[data-style~="liquid"] #view-discussions {
  background-color: var(--bg-base);
  background-image:
    radial-gradient(120% 60% at 50% -20%,
      color-mix(in srgb, var(--accent-blue) 12%, transparent) 0%,
      color-mix(in srgb, var(--accent-blue) 5%, transparent) 38%,
      transparent 72%),
    linear-gradient(180deg,
      transparent 78%,
      color-mix(in srgb, var(--accent-blue) 4%, transparent) 100%);
  background-attachment: fixed;
  background-repeat: no-repeat;
  background-size: cover;
}

:root[data-style~="liquid"] #view-discussions .page-header {
  background: color-mix(in srgb, var(--bg-base) 55%, transparent);
  backdrop-filter: blur(20px) saturate(160%);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
  border-bottom-color: color-mix(in srgb, var(--accent-blue) 14%, var(--border));
}

:root[data-style~="liquid"] #view-discussions .conv-body {
  background: transparent;
}

/* Conv list panel intentionally NOT retinted — on mobile it becomes an
   absolute slide-out drawer that needs to stay opaque (background:
   var(--bg-surface) from the mobile breakpoint at line ~2773). A
   translucent override breaks the drawer's opacity over the chat behind. */
:root[data-style~="liquid"] #view-discussions .conv-list-col {
  border-right-color: color-mix(in srgb, var(--accent-blue) 14%, var(--border)) !important;
}

/* Conv rows — drop the inline opaque background so the translucent panel
   reads through. JS writes item.style.background on hover/active, so the
   resting state needs !important to win. The .conv-list-item::before
   capsule already exists in default CSS and paints from --accent-blue;
   under glass we just soften the at-rest pill so the gutter has a faint
   accent presence. */
:root[data-style~="liquid"] #view-discussions .conv-list-item {
  background: transparent !important;
  border-bottom-color: color-mix(in srgb, var(--accent-blue) 10%, var(--border)) !important;
  transition: background-color 200ms ease;
}

:root[data-style~="liquid"] #view-discussions .conv-list-item--active {
  background: color-mix(in srgb, var(--accent-blue) 10%, transparent) !important;
}

:root[data-style~="liquid"] #view-discussions .conv-list-item--pinned-profile {
  background: color-mix(in srgb, var(--accent-blue) 6%, transparent) !important;
}

:root[data-style~="liquid"] #view-discussions .conv-list-item--active::before,
:root[data-style~="liquid"] #view-discussions .conv-list-item--pinned-profile::before {
  background: var(--accent-blue);
}

:root[data-style~="liquid"] #view-discussions .conv-detail-header {
  background: color-mix(in srgb, var(--bg-base) 55%, transparent);
  backdrop-filter: blur(20px) saturate(160%);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
  border-bottom-color: color-mix(in srgb, var(--accent-blue) 14%, var(--border));
}

:root[data-style~="liquid"] #view-discussions .conv-list-toggle {
  /* Match #wiki-rail-toggle / .wiki-rail-collapse-btn under glass:
     opaque-ish fill + tinted hairline border so the circle is visible
     against the panel in both light and dark themes. */
  background: color-mix(in srgb, var(--bg-card) 82%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent-blue) 28%, var(--border));
}
:root[data-style~="liquid"] #view-discussions .conv-list-toggle:hover {
  background: color-mix(in srgb, var(--bg-card) 92%, transparent);
  border-color: var(--accent-blue);
}

:root[data-style~="liquid"] #view-discussions .new-chat-meta-row {
  background: color-mix(in srgb, var(--bg-base) 55%, transparent) !important;
  backdrop-filter: blur(20px) saturate(160%);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
  border-bottom-color: color-mix(in srgb, var(--accent-blue) 14%, var(--border)) !important;
}

:root[data-style~="liquid"] #view-discussions .conv-list-participants-capsule,
:root[data-style~="liquid"] #view-discussions .participants-capsule {
  background: color-mix(in srgb, var(--bg-elevated) 50%, transparent) !important;
  border-color: color-mix(in srgb, var(--accent-blue) 14%, var(--border)) !important;
}

/* Message bubbles — conversations.js sets inline `border-left: 3px solid
   ${identityColor}` + a solid bg. Kill the coloured peek with the `border`
   shorthand + !important (resets all four edges including width), and
   retint the bubble to translucent glass.
   Scope covers both #view-discussions (conversations) AND #wiki-center-panel
   (Identity → section "Chat to refine") so both surfaces render the same
   translucent bubble with the slider-controlled hairline border. */
:root[data-style~="liquid"] #view-discussions .conv-excerpt-bubble,
:root[data-style~="liquid"] #wiki-center-panel .conv-excerpt-bubble {
  background: color-mix(in srgb, var(--bg-elevated) 50%, transparent) !important;
  backdrop-filter: blur(14px) saturate(150%);
  -webkit-backdrop-filter: blur(14px) saturate(150%);
  /* Border opacity is driven by --incoming-bubble-border-intensity.
     The inner color-mix is the calibrated baseline color (10% accent
     tint on var(--border)); the outer mix fades that to transparent
     so intensity=0 fully removes all 4 edges instead of falling
     through to a plain var(--border) layer underneath. */
  border: 1px solid color-mix(
    in srgb,
    color-mix(in srgb, var(--accent-blue) 10%, var(--border))
      calc(clamp(0, var(--incoming-bubble-border-intensity, 20), 200) * 1%),
    transparent
  ) !important;
  border-radius: 20px !important;
  padding: 10px 14px !important;
}

/* iMessage-blue treatment for the user's own bubbles — solid accent-blue
   under all themes (including liquid) so "Me" matches the .btn-primary
   "New" button exactly with no transparency tint. Covers both
   #view-discussions and #wiki-center-panel so the Identity refine chat
   gets the same iMessage-blue Me bubble as conversations. */
:root[data-style~="liquid"] #view-discussions .conv-excerpt-bubble.is-me,
:root[data-style~="liquid"] #wiki-center-panel .conv-excerpt-bubble.is-me {
  background: var(--accent-blue) !important;
  border: 1px solid var(--accent-blue) !important;
}

/* Text color on the user's own bubble mirrors .btn-primary: white across
   every theme so the bubble reads as iMessage-style white-on-blue. */
.conv-excerpt-bubble.is-me {
  color: #fff;
}

:root[data-style~="liquid"] #view-discussions .chain-silent-row {
  background: color-mix(in srgb, var(--bg-elevated) 45%, transparent);
  border-color: color-mix(in srgb, var(--accent-blue) 12%, var(--border));
  backdrop-filter: blur(14px) saturate(150%);
  -webkit-backdrop-filter: blur(14px) saturate(150%);
}

:root[data-style~="liquid"] #view-discussions .mm-chat-composer {
  background: color-mix(in srgb, var(--bg-base) 55%, transparent);
  backdrop-filter: blur(20px) saturate(160%);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
  border-top: 1px solid color-mix(in srgb, var(--accent-blue) 14%, var(--border)) !important;
}

:root[data-style~="liquid"] #view-discussions .pill-composer {
  background: color-mix(in srgb, var(--bg-surface) 50%, transparent);
  border-color: color-mix(in srgb, var(--accent-blue) 14%, var(--border));
}
:root[data-style~="liquid"] #view-discussions .pill-composer:focus-within {
  border-color: var(--accent-blue);
}

/* ── Account view ──────────────────────────────────────────────────────────── */

:root[data-style~="liquid"] #view-account {
  background-color: var(--bg-base);
  background-image:
    radial-gradient(120% 60% at 50% -20%,
      color-mix(in srgb, var(--accent-blue) 12%, transparent) 0%,
      color-mix(in srgb, var(--accent-blue) 5%, transparent) 38%,
      transparent 72%),
    linear-gradient(180deg,
      transparent 78%,
      color-mix(in srgb, var(--accent-blue) 4%, transparent) 100%);
  background-attachment: fixed;
  background-repeat: no-repeat;
  background-size: cover;
}

:root[data-style~="liquid"] .account-panel {
  background: color-mix(in srgb, var(--bg-card) 55%, transparent);
  backdrop-filter: blur(20px) saturate(160%);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
  border: 1px solid color-mix(in srgb, var(--accent-blue) 10%, var(--border));
  border-radius: 16px;
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, var(--text-primary) 5%, transparent),
    0 12px 32px -20px color-mix(in srgb, var(--bg-base) 60%, black);
}

:root[data-style~="liquid"] .account-panel--danger {
  border-color: color-mix(in srgb, var(--accent-red) 30%, var(--border));
}

:root[data-style~="liquid"] .account-panel-title {
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  color: var(--text-muted);
  border-bottom-color: color-mix(in srgb, var(--accent-blue) 14%, var(--border));
  background: transparent;
}

:root[data-style~="liquid"] .account-panel-title--danger {
  color: var(--accent-red);
  border-bottom-color: color-mix(in srgb, var(--accent-red) 24%, var(--border));
}

:root[data-style~="liquid"] .account-field-label {
  text-transform: none;
  letter-spacing: 0;
  font-size: 11px;
  color: var(--text-muted);
}

:root[data-style~="liquid"] .account-field-value {
  font-size: 13px;
}

:root[data-style~="liquid"] .account-danger-row {
  border-bottom-color: color-mix(in srgb, var(--accent-red) 16%, var(--border));
}

/* Error banner — stay solid + red-tinted so it reads as an alert, not chrome. */
:root[data-style~="liquid"] .account-error {
  background: color-mix(in srgb, var(--accent-red) 10%, var(--bg-surface));
  border: 1px solid color-mix(in srgb, var(--accent-red) 35%, var(--border));
  color: var(--accent-red);
  border-radius: 10px;
  padding: 10px 12px;
  font-size: 13px;
  line-height: 1.5;
}

:root[data-style~="liquid"] .billing-balance-row {
  border-bottom-color: color-mix(in srgb, var(--accent-blue) 14%, var(--border));
}

:root[data-style~="liquid"] .billing-balance-label,
:root[data-style~="liquid"] .billing-section-title {
  text-transform: none;
  letter-spacing: 0;
  font-weight: 500;
  color: var(--text-muted);
  font-size: 12px;
}

:root[data-style~="liquid"] .billing-frozen-banner {
  background: color-mix(in srgb, var(--accent-red) 10%, var(--bg-surface));
  border: 1px solid color-mix(in srgb, var(--accent-red) 35%, var(--border));
  border-radius: 12px;
}

:root[data-style~="liquid"] .billing-card {
  background: color-mix(in srgb, var(--bg-surface) 55%, transparent);
  backdrop-filter: blur(16px) saturate(160%);
  -webkit-backdrop-filter: blur(16px) saturate(160%);
  border: 1px solid color-mix(in srgb, var(--accent-blue) 12%, var(--border));
  border-radius: 14px;
}

:root[data-style~="liquid"] .billing-card-error {
  color: var(--accent-red);
}

:root[data-style~="liquid"] .billing-empty {
  color: var(--text-muted);
}

:root[data-style~="liquid"] .billing-history-row:nth-child(odd) {
  background: color-mix(in srgb, var(--bg-surface) 35%, transparent);
}

:root[data-style~="liquid"] .billing-history-type {
  text-transform: none;
  letter-spacing: 0;
}

:root[data-style~="liquid"] .billing-history-tag {
  border-color: color-mix(in srgb, var(--accent-blue) 14%, var(--border));
}

/* ── Onboarding flow (modal overlay) ───────────────────────────────────────── */

:root[data-style~="liquid"] #onboarding-overlay {
  background: color-mix(in srgb, var(--bg-base) 55%, transparent);
  backdrop-filter: blur(14px) saturate(160%);
  -webkit-backdrop-filter: blur(14px) saturate(160%);
}

:root[data-style~="liquid"] #onboarding-overlay .onboarding-card,
:root[data-style~="liquid"] #onboarding-overlay .onboarding-card.onboarding-card-v2 {
  background: color-mix(in srgb, var(--bg-card) 55%, transparent);
  backdrop-filter: blur(28px) saturate(180%);
  -webkit-backdrop-filter: blur(28px) saturate(180%);
  border: 1px solid color-mix(in srgb, var(--accent-blue) 12%, var(--border));
  border-radius: 20px;
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, var(--text-primary) 6%, transparent),
    0 24px 64px -24px color-mix(in srgb, var(--bg-base) 60%, black);
}

:root[data-style~="liquid"] .onboarding-step-indicator {
  text-transform: none;
  letter-spacing: 0;
  font-size: 12px;
  color: var(--text-muted);
}

:root[data-style~="liquid"] .onboarding-progress {
  background: color-mix(in srgb, var(--accent-blue) 12%, transparent);
}
:root[data-style~="liquid"] .onboarding-progress-fill {
  background: var(--accent-blue);
}

:root[data-style~="liquid"] .onboarding-close,
:root[data-style~="liquid"] .onboarding-back {
  background: color-mix(in srgb, var(--bg-surface) 50%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent-blue) 14%, var(--border));
  color: var(--text-secondary);
}
:root[data-style~="liquid"] .onboarding-close:hover,
:root[data-style~="liquid"] .onboarding-back:hover {
  background: color-mix(in srgb, var(--accent-blue) 12%, transparent);
  border-color: var(--accent-blue);
  color: var(--text-primary);
}

:root[data-style~="liquid"] .onboarding-footer,
:root[data-style~="liquid"] .onb-footer {
  background: transparent;
  border-top: 1px solid color-mix(in srgb, var(--accent-blue) 14%, var(--border));
}

:root[data-style~="liquid"] .onboarding-title {
  font-weight: 500;
  letter-spacing: 0;
}

:root[data-style~="liquid"] .onb-subtle {
  color: var(--text-muted);
}

/* Error banner — stays solid red-tinted so it reads as alert, not chrome. */
:root[data-style~="liquid"] .onb-error {
  background: color-mix(in srgb, var(--accent-red) 10%, var(--bg-surface));
  border: 1px solid color-mix(in srgb, var(--accent-red) 35%, var(--border));
  color: var(--accent-red);
  border-radius: 10px;
}

:root[data-style~="liquid"] .onb-textarea,
:root[data-style~="liquid"] .onb-vignette-correction-input {
  background: color-mix(in srgb, var(--bg-surface) 50%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent-blue) 12%, var(--border));
}
:root[data-style~="liquid"] .onb-textarea:focus,
:root[data-style~="liquid"] .onb-vignette-correction-input:focus {
  border-color: var(--accent-blue);
}

:root[data-style~="liquid"] .onb-path-card {
  background: color-mix(in srgb, var(--bg-card) 50%, transparent);
  backdrop-filter: blur(14px) saturate(150%);
  -webkit-backdrop-filter: blur(14px) saturate(150%);
  border: 1px solid color-mix(in srgb, var(--accent-blue) 10%, var(--border));
  border-radius: 12px;
}
:root[data-style~="liquid"] .onb-path-header {
  text-transform: none;
  letter-spacing: 0;
  font-weight: 500;
  color: var(--text-muted);
}

:root[data-style~="liquid"] .onb-chip {
  background: color-mix(in srgb, var(--bg-elevated) 50%, transparent);
  border-color: color-mix(in srgb, var(--accent-blue) 14%, var(--border));
}
:root[data-style~="liquid"] .onb-chip:hover {
  background: color-mix(in srgb, var(--accent-blue) 10%, transparent);
  border-color: color-mix(in srgb, var(--accent-blue) 28%, var(--border));
}
:root[data-style~="liquid"] .onb-chip.selected {
  background: var(--accent-blue);
  border-color: var(--accent-blue);
}

:root[data-style~="liquid"] .onb-card,
:root[data-style~="liquid"] .onb-section-card,
:root[data-style~="liquid"] .onb-vignette-card {
  background: color-mix(in srgb, var(--bg-card) 50%, transparent);
  backdrop-filter: blur(14px) saturate(150%);
  -webkit-backdrop-filter: blur(14px) saturate(150%);
  border: 1px solid color-mix(in srgb, var(--accent-blue) 10%, var(--border));
  border-radius: 12px;
}
:root[data-style~="liquid"] .onb-card.status-done {
  background: color-mix(in srgb, var(--accent-green, #50c878) 6%, color-mix(in srgb, var(--bg-card) 50%, transparent));
}
:root[data-style~="liquid"] .onb-card.status-in_progress {
  background: color-mix(in srgb, var(--accent-blue) 6%, color-mix(in srgb, var(--bg-card) 50%, transparent));
}
:root[data-style~="liquid"] .onb-card.expanded {
  border-color: color-mix(in srgb, var(--accent-blue) 28%, var(--border));
  background: color-mix(in srgb, var(--bg-card) 60%, transparent);
}
:root[data-style~="liquid"] .onb-card-header:hover {
  background: color-mix(in srgb, var(--accent-blue) 8%, transparent);
}
:root[data-style~="liquid"] .onb-card-body {
  border-top-color: color-mix(in srgb, var(--accent-blue) 12%, var(--border));
}

/* Bubbles — under glass the parent expanded card is already translucent, so
   the bubble needs real opacity + a hairline to read as a distinct surface
   instead of melting into the card behind it. Mirrors the iMessage-style
   radius from .conv-excerpt-bubble. */
:root[data-style~="liquid"] .onb-bubble {
  background: color-mix(in srgb, var(--bg-elevated) 88%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent-blue) 12%, var(--border));
  border-radius: 18px;
  padding: 10px 14px;
}
:root[data-style~="liquid"] .onb-bubble-user {
  background: color-mix(in srgb, var(--accent-blue) 22%, transparent);
  border-color: color-mix(in srgb, var(--accent-blue) 32%, var(--border));
}
:root[data-style~="liquid"] .onb-bubble-label {
  text-transform: none;
  letter-spacing: 0;
  color: var(--text-muted);
}

:root[data-style~="liquid"] .onb-composer-inline-row {
  background: color-mix(in srgb, var(--bg-surface) 50%, transparent);
  border-color: color-mix(in srgb, var(--accent-blue) 14%, var(--border));
}
:root[data-style~="liquid"] .onb-composer-inline-row:focus-within {
  border-color: var(--accent-blue);
}

:root[data-style~="liquid"] .onb-add-topic-toggle {
  background: color-mix(in srgb, var(--bg-surface) 50%, transparent);
  border-color: color-mix(in srgb, var(--accent-blue) 12%, var(--border));
}
:root[data-style~="liquid"] .onb-add-topic-toggle:hover:not([disabled]) {
  background: color-mix(in srgb, var(--accent-blue) 10%, transparent);
  border-color: var(--accent-blue);
}
:root[data-style~="liquid"] .onb-add-topic-panel {
  background: color-mix(in srgb, var(--bg-card) 55%, transparent);
  backdrop-filter: blur(18px) saturate(160%);
  -webkit-backdrop-filter: blur(18px) saturate(160%);
  border: 1px solid color-mix(in srgb, var(--accent-blue) 12%, var(--border));
  border-radius: 12px;
}
:root[data-style~="liquid"] .onb-add-topic-header {
  text-transform: none;
  letter-spacing: 0;
  color: var(--text-muted);
}
:root[data-style~="liquid"] .onb-add-topic-row:hover:not([disabled]) {
  background: color-mix(in srgb, var(--accent-blue) 10%, transparent);
}

:root[data-style~="liquid"] .onb-section-divider {
  text-transform: none;
  letter-spacing: 0;
  color: var(--text-muted);
  font-weight: 500;
}
:root[data-style~="liquid"] .onb-section-divider::before,
:root[data-style~="liquid"] .onb-section-divider::after {
  background: color-mix(in srgb, var(--accent-blue) 14%, var(--border));
}

:root[data-style~="liquid"] .onb-vignette-card--error {
  border-color: color-mix(in srgb, var(--accent-red) 24%, var(--border));
}
:root[data-style~="liquid"] .onb-vignette-title {
  text-transform: none;
  letter-spacing: 0;
  color: var(--text-muted);
  font-weight: 500;
}

:root[data-style~="liquid"] .onb-demo-pill {
  background: color-mix(in srgb, var(--accent-blue) 12%, transparent);
  border-color: color-mix(in srgb, var(--accent-blue) 35%, var(--border));
  text-transform: none;
  letter-spacing: 0;
}

@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  :root[data-style~="liquid"] .help-section,
  :root[data-style~="liquid"] .discover-card,
  :root[data-style~="liquid"] .discover-toolbar,
  :root[data-style~="liquid"] #wiki-left-panel,
  :root[data-style~="liquid"] .identity-section-card,
  :root[data-style~="liquid"] #view-wiki > .page-header,
  :root[data-style~="liquid"] .wiki-menu-bar,
  :root[data-style~="liquid"] #view-discussions .page-header,
  :root[data-style~="liquid"] #view-discussions .conv-detail-header,
  :root[data-style~="liquid"] #view-discussions .mm-chat-composer,
  :root[data-style~="liquid"] #view-discussions .pill-composer,
  :root[data-style~="liquid"] .account-panel,
  :root[data-style~="liquid"] .billing-card,
  :root[data-style~="liquid"] .onboarding-card,
  :root[data-style~="liquid"] .onboarding-card.onboarding-card-v2,
  :root[data-style~="liquid"] .onb-path-card,
  :root[data-style~="liquid"] .onb-card,
  :root[data-style~="liquid"] .onb-section-card,
  :root[data-style~="liquid"] .onb-vignette-card,
  :root[data-style~="liquid"] .onb-add-topic-panel { background: var(--bg-card); }
  :root[data-style~="liquid"] #onboarding-overlay { background: rgba(1, 4, 9, 0.7); }
  :root[data-style~="liquid"] .discover-overlay-panel,
  :root[data-style~="liquid"] #wiki-left-panel,
  :root[data-style~="liquid"] #view-discussions .new-chat-meta-row { background: var(--bg-card) !important; }
}

/* ─── Wiki menu-bar capsules ──────────────────────────────────────────────────
   Shared chrome for the wiki center-panel menu bar's two pill controls:
   the page-picker dropdown trigger and the list/graph view toggle. Sibling
   capsules to .top-bar-core-picker / .pill-composer — same --bg-base fill,
   1px --border rim, full pill radius — so they participate in the same glass
   specular rim treatment when data-style~="glass" is active. */

.wiki-page-picker {
  box-sizing: border-box;
  background: var(--bg-base);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  color: var(--text-primary);
  font-family: var(--font-ui);
  font-size: 13px;
  font-weight: var(--fw-medium);
  line-height: 1.2;
  padding: calc(6px + var(--nav-spacing-offset)) 14px;
  outline: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.wiki-view-toggle {
  display: flex;
  align-items: center;
  gap: 0;
  flex-shrink: 0;
  background: var(--bg-base);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 2px;
}

/* ─── Glass — specular edge glare ─────────────────────────────────────────────
   The Glass surface style is Liquid PLUS a thin, Apple-style specular highlight
   that traces the rim of circles and capsules. Activated when the root carries
   `data-style="liquid glass"` (token-list selector). A single ::after pseudo
   overlays the host element, painted with a conic-gradient and masked to the
   rim only via `padding: 1px` + `mask-composite: exclude`. The glare layers on
   top of the existing Liquid hairline border, never replaces it.

   Light theme variant: white-on-white disappears, so light-mode glare uses a
   soft accent tint instead of pure white. See :root.light[data-style~="glass"]
   block at the bottom of this section.

   Targets:
   - .conv-list-toggle             (rail toggle circle in conversation header)
   - .wiki-rail-collapse-btn       (desktop wiki rail collapse circle)
   - #wiki-rail-toggle             (mobile wiki rail hamburger circle)
   - .sidebar-core-picker          (sidebar Core picker capsule)
   - .top-bar-core-picker          (mobile top-bar Core picker capsule)
   - .top-bar-search .pill-composer (search trigger — pill that collapses to a
                                     36px circle when not expanded)
   - .wiki-page-picker             (wiki center-panel "Pages — …" dropdown trigger)
   - .wiki-view-toggle             (wiki menu-bar list↔graph segmented pill)
   - .chip                         (selectable filter pills; opted in so dense
                                     chip groups pick up the same raised rim)

   Border treatment: the same selector list (minus .chip--selected, which keeps
   its accent-blue rim) also adopts var(--border-glass) — a slightly lifted
   border color so the rim still reads as "raised" when the glare is dialed
   low via --glass-glare-brightness.

   Implementation note: each host needs `position: relative` (already set on
   .top-bar-search wrappers; we re-assert on the toggle/circle classes to be
   safe). The ::after inherits border-radius from the host so it adapts whether
   the host is a circle (999px) or rounded capsule (--radius-sm). */

:root[data-style~="glass"] .conv-list-toggle,
:root[data-style~="glass"] .wiki-rail-collapse-btn,
:root[data-style~="glass"] #wiki-rail-toggle,
:root[data-style~="glass"] .sidebar-core-picker,
:root[data-style~="glass"] .top-bar-core-picker,
:root[data-style~="glass"] .top-bar-search .pill-composer,
:root[data-style~="glass"] .wiki-page-picker,
:root[data-style~="glass"] .wiki-view-toggle,
:root[data-style~="glass"] .chip {
  position: relative;
}

/* Glass-rim border color — applied to capsules that carry the glare so the
   border reads as "raised" even at low --glass-glare-brightness. Skipped on
   .chip--selected because that state already paints an accent-blue rim. */
:root[data-style~="glass"] .conv-list-toggle,
:root[data-style~="glass"] .wiki-rail-collapse-btn,
:root[data-style~="glass"] #wiki-rail-toggle,
:root[data-style~="glass"] .sidebar-core-picker,
:root[data-style~="glass"] .top-bar-core-picker,
:root[data-style~="glass"] .wiki-page-picker,
:root[data-style~="glass"] .wiki-view-toggle,
:root[data-style~="glass"] .chip:not(.chip--selected) {
  border-color: var(--border-glass);
}

:root[data-style~="glass"] .conv-list-toggle::after,
:root[data-style~="glass"] .wiki-rail-collapse-btn::after,
:root[data-style~="glass"] #wiki-rail-toggle::after,
:root[data-style~="glass"] .sidebar-core-picker::after,
:root[data-style~="glass"] .top-bar-core-picker::after,
:root[data-style~="glass"] .top-bar-search .pill-composer::after,
:root[data-style~="glass"] .wiki-page-picker::after,
:root[data-style~="glass"] .wiki-view-toggle::after,
:root[data-style~="glass"] .chip::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: 1px;
  pointer-events: none;
  /* Conic-gradient sweeps a bright highlight through the upper-left rim and
     decays to transparent through the lower half. Brightest stop is 315deg
     (upper-left), with a secondary glint at 0deg/45deg (upper-right shoulder)
     to mimic a directional light. */
  background:
    conic-gradient(
      from 0deg,
      rgba(255, 255, 255, 0.55) 0deg,
      rgba(255, 255, 255, 0.25) 45deg,
      rgba(255, 255, 255, 0)    135deg,
      rgba(255, 255, 255, 0)    225deg,
      rgba(255, 255, 255, 0.65) 315deg,
      rgba(255, 255, 255, 0.55) 360deg
    );
  /* Mask to a ring (rim only) via padding-box subtract content-box.
     The `linear-gradient(#000 0 0)` is a solid mask source; the composite
     `exclude` punches out the inner content-box leaving the 1px rim. */
  -webkit-mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
          mask-composite: exclude;
  /* Slight blend so the glare feels like reflected light rather than paint. */
  mix-blend-mode: screen;
  /* 0.9 is the calibrated default; --glass-glare-brightness (0–200, default
     100) linearly scales it so the settings popover slider drives intensity
     in both directions. */
  opacity: calc(0.9 * (var(--glass-glare-brightness, 100) / 100));
}

/* Light theme — pure white glare disappears against light surfaces. Swap the
   bright stops for a faint accent-tinted highlight at lower alpha. Keep the
   transparent lower-half stops so the rim still fades into shadow. */
:root.light[data-style~="glass"] .conv-list-toggle::after,
:root.light[data-style~="glass"] .wiki-rail-collapse-btn::after,
:root.light[data-style~="glass"] #wiki-rail-toggle::after,
:root.light[data-style~="glass"] .sidebar-core-picker::after,
:root.light[data-style~="glass"] .top-bar-core-picker::after,
:root.light[data-style~="glass"] .top-bar-search .pill-composer::after,
:root.light[data-style~="glass"] .wiki-page-picker::after,
:root.light[data-style~="glass"] .wiki-view-toggle::after,
:root.light[data-style~="glass"] .chip::after {
  background:
    conic-gradient(
      from 0deg,
      color-mix(in oklab, var(--accent-blue), white 30%) 0deg,
      color-mix(in oklab, var(--accent-blue) 70%, transparent) 45deg,
      rgba(0, 0, 0, 0)                                   135deg,
      rgba(0, 0, 0, 0)                                   225deg,
      color-mix(in oklab, var(--accent-blue), white 30%) 315deg,
      color-mix(in oklab, var(--accent-blue), white 30%) 360deg
    );
  /* Bring overall alpha down so the tint stays specular, not chromatic.
     Scaled by --glass-glare-brightness (0–200, default 100) for parity with
     the dark variant. */
  opacity: calc(0.35 * (var(--glass-glare-brightness, 100) / 100));
  mix-blend-mode: normal;
}

/* === Discover revamp === */
/* Self-contained block for the Discover view (cards + toolbar + overlay
   sections). All rules use existing CSS variables; revertable as a unit. */

.discover-card {
  /* Inherits .card padding/background; left border is set inline so the
     facet's own color carries through. Falls back to var(--border) when
     color is null. */
  display: flex;
  flex-direction: column;
  transition: border-color var(--transition), transform var(--transition), box-shadow var(--transition);
}

.discover-card:hover {
  /* Don't override the inline left border-color — only hint the right edges. */
  border-top-color: var(--text-muted);
  border-right-color: var(--text-muted);
  border-bottom-color: var(--text-muted);
  transform: translateY(-1px);
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.18);
}

.discover-card-accent {
  /* Reserved hook for future "featured" framing on top of the left border. */
  position: relative;
}

.discover-toolbar {
  position: sticky;
  top: 0;
  z-index: 5;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 24px;
  background: var(--bg-base);
  border-bottom: 1px solid var(--border);
  flex-wrap: wrap;
}

.discover-toolbar-search {
  flex: 1;
  min-width: 0;
  background: var(--bg-surface);
  color: var(--text-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  padding: 7px 12px;
  font-size: 0.875rem;
  outline: none;
  transition: border-color var(--transition);
  /* Strip iOS Safari's native search affordance + macOS dark form-control. */
  -webkit-appearance: none;
  appearance: none;
}

/* Hide the iOS/macOS Safari "x" clear button — we already have full control
   via the input value; the native button reads as a misaligned grey square
   on dark backgrounds. */
.discover-toolbar-search::-webkit-search-decoration,
.discover-toolbar-search::-webkit-search-cancel-button,
.discover-toolbar-search::-webkit-search-results-button,
.discover-toolbar-search::-webkit-search-results-decoration {
  -webkit-appearance: none;
  display: none;
}

.discover-toolbar-search:focus {
  border-color: var(--accent-blue);
}

.discover-toolbar-sort {
  background: var(--bg-surface);
  color: var(--text-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  /* Right pad reserves room for the chevron we draw via background-image,
     since appearance:none strips the native arrow. */
  padding: 7px 30px 7px 10px;
  font-size: 0.85rem;
  cursor: pointer;
  outline: none;
  /* Strip iOS native select styling so the dark theme actually applies. */
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  background-image:
    linear-gradient(45deg, transparent 50%, var(--text-secondary) 50%),
    linear-gradient(135deg, var(--text-secondary) 50%, transparent 50%);
  background-position:
    calc(100% - 14px) 50%,
    calc(100% - 9px)  50%;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}

.discover-toolbar-sort:focus {
  border-color: var(--accent-blue);
}

@media (max-width: 767px) {
  .discover-toolbar {
    padding: 8px 16px;
    gap: 8px;
  }
  .discover-toolbar-sort {
    /* Slightly tighter on phones where horizontal real estate is precious. */
    padding: 7px 26px 7px 8px;
  }
}

.discover-chip {
  display: inline-flex;
  align-items: center;
  padding: 2px 8px;
  font-size: 0.72rem;
  line-height: 1.6;
  border-radius: var(--radius-pill, 100px);
  background: var(--bg-elevated);
  color: var(--text-primary);
  border: 1px solid var(--border);
  white-space: nowrap;
}

.discover-chip-muted {
  opacity: 0.85;
  color: var(--text-secondary);
}

.discover-overlay-section {
  display: block;
}

.discover-overlay-prompt {
  text-align: left;
  height: var(--input-height);
  padding: 0 18px;
  box-sizing: border-box;
  font-size: 0.875rem;
  line-height: 1.45;
  background: var(--bg-elevated);
  color: var(--text-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  cursor: pointer;
  transition: border-color var(--transition), background var(--transition);
  font-family: inherit;
}

.discover-overlay-prompt:hover {
  border-color: var(--accent-blue);
  background: var(--bg-hover);
}

/* ─── Onboarding revamp (adaptive 3-step Core build) ──────────────────────────
   Replaces the original placeholder shell. The base .onboarding-card,
   .onboarding-header, .onboarding-step-indicator, .onboarding-close,
   .onboarding-body, .onboarding-title styles above stay live; the new layout
   widens the card on desktop so the Step 2 card list and Step 3 section
   preview fit comfortably. */

#onboarding-overlay .onboarding-card.onboarding-card-v2 {
  max-width: 720px;
  /* Tighter vertical cap than the base .onboarding-card (which goes nearly
     full-viewport at 100vh - 32px). Step 2 chats can grow long; the body
     already has overflow-y:auto so it scrolls inside. We just want the
     card itself to stop growing well short of the viewport so it reads as
     a sheet floating in space, not as a full-screen takeover. Caps at
     720px on tall screens and leaves ~96px (48px top + 48px bottom) of
     breathing room on shorter ones. */
  max-height: min(720px, calc(100vh - 96px));
}

.onb-subtle {
  margin: 0 0 20px;
  font-size: 0.85rem;
  color: var(--text-muted);
  line-height: 1.5;
}
.onb-error {
  margin: 8px 0;
  padding: 8px 10px;
  border: 1px solid var(--accent-red);
  border-radius: var(--radius-sm);
  background: rgba(255, 70, 70, 0.08);
  color: var(--accent-red);
  font-size: 0.85rem;
}
.onb-spacer { flex: 1; }
.onb-footer {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 24px;
  padding-top: 18px;
  border-top: 1px solid var(--border);
}

/* ── Step 1 ── */

.onb-textarea {
  width: 100%;
  box-sizing: border-box;
  padding: 10px 12px;
  background: var(--bg-base);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text-primary);
  font-family: var(--font-ui);
  font-size: 0.9rem;
  line-height: 1.5;
  resize: vertical;
  min-height: 96px;
}
.onb-textarea:focus {
  outline: none;
  border-color: var(--accent-blue);
}

/* Step 1 two-pane layout — left pane = freeform write, right pane = topic
   chips. Each pane is a bordered card so the visual parallelism reads as
   "two equal options" instead of "input with filter chips". Stacks at the
   720px breakpoint (the same breakpoint as the onboarding card itself). */
.onb-paths {
  display: flex;
  gap: 16px;
  margin: 8px 0 12px;
  align-items: stretch;
}
.onb-path-card {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 18px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-card);
}
.onb-path-header {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-secondary);
  font-weight: var(--fw-semibold);
  display: flex;
  align-items: center;
  gap: 4px;
}
.onb-path-icon {
  font-size: 0.95rem;
  opacity: 0.85;
}
@media (max-width: 720px) {
  .onb-paths { flex-direction: column; }
}

.onb-chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0;
}
.onb-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 6px 12px;
  background: var(--bg-base);
  border: 1px solid var(--border);
  border-radius: 999px;
  color: var(--text-primary);
  font-family: var(--font-ui);
  font-size: 0.82rem;
  cursor: pointer;
  transition: background 120ms, border-color 120ms, color 120ms;
}
.onb-chip:hover { background: var(--bg-hover); }
.onb-chip.selected {
  background: var(--accent-blue);
  border-color: var(--accent-blue);
  color: #fff;
}
.onb-chip-emoji { font-size: 0.95rem; }

/* Add-your-own topic input — lives below the chip row in Step 1's Tap pane.
   Visual language mirrors .onb-textarea (same border, radius, font) so it
   reads as an input rather than a chip. Pairs with a compact .onb-chip-
   custom-add button that uses the same selected-chip accent color. */
.onb-chip-custom-row {
  display: flex;
  gap: 6px;
  margin-top: 4px;
  align-items: stretch;
}
.onb-chip-custom-input {
  flex: 1;
  min-width: 0;
  box-sizing: border-box;
  padding: 6px 12px;
  background: var(--bg-base);
  border: 1px solid var(--border);
  border-radius: 999px;
  color: var(--text-primary);
  font-family: var(--font-ui);
  font-size: 0.82rem;
  line-height: 1.4;
}
.onb-chip-custom-input:focus {
  outline: none;
  border-color: var(--accent-blue);
}
.onb-chip-custom-add {
  padding: 6px 14px;
  background: var(--bg-base);
  border: 1px solid var(--border);
  border-radius: 999px;
  color: var(--text-primary);
  font-family: var(--font-ui);
  font-size: 0.82rem;
  cursor: pointer;
  transition: background 120ms, border-color 120ms, color 120ms;
}
.onb-chip-custom-add:hover {
  background: var(--accent-blue);
  border-color: var(--accent-blue);
  color: #fff;
}

/* ── Step 2 (cards) ── */

.onb-card-list {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-top: 16px;
}
.onb-card {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-base);
  overflow: hidden;
  transition: border-color 120ms;
}
/* Expanded cards return to the base background regardless of status. The
   status tint (in_progress blue / done green) stays visible on collapsed
   cards as a progress signal in the list; once a card is open, the message
   thread inside should read against a clean white surface, not a tinted
   one. Specificity-wise the .expanded rule must override the .status-*
   rules below — declaration order does that here. */
.onb-card.status-done { background: rgba(80, 200, 120, 0.05); }
.onb-card.status-in_progress { background: rgba(91, 141, 239, 0.04); }
.onb-card.expanded { border-color: var(--accent-blue); background: var(--bg-base); }

.onb-card-header {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 14px 16px;
  cursor: pointer;
  user-select: none;
}
.onb-card-header:hover { background: var(--bg-hover); }
.onb-card-status {
  display: inline-flex;
  width: 18px;
  height: 18px;
  align-items: center;
  justify-content: center;
  font-size: 0.85rem;
  color: var(--text-muted);
  flex-shrink: 0;
}
.onb-card.status-done .onb-card-status { color: var(--accent-green, #50c878); }
.onb-card.status-in_progress .onb-card-status { color: var(--accent-blue); }
.onb-card-title {
  flex: 1;
  font-size: 0.9rem;
  color: var(--text-primary);
  font-weight: var(--fw-medium, 500);
}
.onb-card-toggle {
  color: var(--text-muted);
  font-size: 0.85rem;
}

.onb-card-body {
  padding: 16px 18px 18px;
  border-top: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.onb-bubble {
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  background: var(--bg-elevated);
  font-size: 0.85rem;
  line-height: 1.5;
  /* iMessage-style alignment — the chat list (.onb-card-body) is flex-column,
     so align-self places each bubble against the leading or trailing edge.
     max-width leaves explicit empty space on the opposite side so the
     direction reads at a glance even on narrow viewports. */
  max-width: 80%;
  align-self: flex-start;
}
.onb-bubble-user {
  background: rgba(91, 141, 239, 0.08);
  align-self: flex-end;
}
.onb-bubble-label {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-muted);
  margin-bottom: 2px;
}
.onb-bubble-text { white-space: pre-wrap; word-wrap: break-word; color: var(--text-primary); }

.onb-composer {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-top: 48px;
}
/* Single-row composer pill — textarea (or input) on the leading edge, an
   action button (Send / Create / etc.) sitting INSIDE the same capsule on
   the trailing edge as a smaller nested pill with ~4px breathing room on
   all sides. Border + focus ring sit on the wrapper, NOT on the input, so
   the two children read as one control. Used by:
     - onboarding step 2 + step 3 composers (.onb-composer-* — original)
     - wiki section-refine, Core/facet chat, "+ New section" Create
     - conversations existing-convo + new-chat footers
     - discover-overlay "Ask anything"
   New surfaces should prefer the generic .pill-composer / .pill-composer-input
   / .pill-composer-action triplet. The .onb-composer-* selectors are kept
   as aliases for the existing onboarding markup. */
.onb-composer-inline-row,
.pill-composer {
  display: flex;
  /* Center-align children so the textarea's single-line text shares the
     pill's vertical center with the Send button. With stretch (flex default)
     the textarea inflates to the pill's height while its text stays glued to
     the content-box top — text floats up, button stays mid-line, baselines
     diverge. Autosize multi-line growth still works: the textarea sets its
     own height, the pill grows with it, and align-items:center keeps the
     button vertically centered against the taller surface. */
  align-items: center;
  /* Floor the pill height so surfaces without a nested action button (e.g.
     the top-bar global search) still read as a 32px capsule. Composers with
     a Send/Create button match this exactly via the button's 24+4+4 margin
     box; the floor is just insurance for the button-less case. */
  min-height: 32px;
  background: var(--bg-base);
  border: 1px solid var(--border);
  /* Base shape is pill (radius gets clamped to height/2 by the browser at
     the single-line ~38px composer height). Surfaces wired to
     components/autosize.js override this when the inner textarea grows
     past 1 line — `.autosize-paint[data-autosize-shape='multi']` drops
     the radius to var(--radius-sm) (the message-bubble radius) so the
     multi-line composer reads as the same rounded rect as the bubbles it
     produces. Static pills (e.g. the wiki "+ New section" Create input,
     which is a single-line <input> with nothing to morph into) keep the
     pill silhouette because they never get the .autosize-paint class.
     Net result: every chat-style composer reads as a pill at rest, and
     only the textareas with auto-grow turn into rounded rects. */
  border-radius: var(--radius-pill);
  transition: border-color 120ms;
}
.onb-composer-inline-row:focus-within,
.pill-composer:focus-within { border-color: var(--accent-blue); }

.onb-composer-input,
.pill-composer-input {
  flex: 1;
  min-width: 0;
  box-sizing: border-box;
  padding: 4px 12px;
  background: transparent;
  border: none;
  color: var(--text-primary);
  font-family: var(--font-ui);
  font-size: 0.85rem;
  line-height: 1.45;
  resize: none;
  /* Capsule = 32px = button height 24 + 4+4 margin. Locking input height
     equal to button margin-box kills the align-self:center offset so the
     visible top/bottom gap equals the trailing margin (both 4px). */
  min-height: 32px;
  max-height: 160px;
  overflow-y: auto;
}
.onb-composer-input:focus,
.pill-composer-input:focus {
  outline: none;
  /* The global textarea:focus rule adds a 3px box-shadow glow. Inside the
     composer pill the textarea has no border-radius, so the shadow draws as
     a square around the inner field while the visible pill is a rounded
     rect. Strip the inner glow — the outer pill's :focus-within border
     color is the active-state cue. */
  box-shadow: none;
}

/* Strip border/bg/radius from any pre-styled input/textarea nested inside
   the pill so the outer capsule is the only visible border. Specificity
   beats .composer-textarea / .input / .textarea base rules. */
.pill-composer > .composer-textarea,
.pill-composer > .input,
.pill-composer > .textarea,
.pill-composer > textarea,
.pill-composer > input {
  background: transparent;
  border: none;
  border-radius: 0;
  box-shadow: none;
  flex: 1;
  min-width: 0;
  /* Drop the base 38px floor that .composer-textarea ships with. The pill's
     height is driven by the Send button's margin-box (24+4+4 = 32px); the
     textarea sizes to its own single-line content (~19px) and is vertically
     centered inside the pill by align-items:center on the parent. Result:
     the placeholder/text shares the pill's center with the button. autosize.js
     drives multi-line growth via inline height, unaffected by min-height. */
  min-height: 0;
  padding: 0 12px;
  font-size: 0.85rem;
  line-height: 1.45;
}
.pill-composer > .composer-textarea:focus,
.pill-composer > .input:focus,
.pill-composer > .textarea:focus,
.pill-composer > textarea:focus,
.pill-composer > input:focus {
  border: none;
  box-shadow: none;
  outline: none;
}

/* Mirror of the .pill-composer > X strip rule for onboarding's parallel
   wrapper class. Onboarding composers (.onb-composer-inline-row) hold an
   .onb-composer-input textarea — without this override the textarea kept
   its 32px floor and the text sat glued to the content-box top while the
   centered parent + Send button stayed mid-pill. Result: same baseline
   misalignment the .pill-composer surfaces hit before. */
.onb-composer-inline-row > .composer-textarea,
.onb-composer-inline-row > .input,
.onb-composer-inline-row > .textarea,
.onb-composer-inline-row > textarea,
.onb-composer-inline-row > input,
.onb-composer-inline-row > .onb-composer-input {
  background: transparent;
  border: none;
  border-radius: 0;
  box-shadow: none;
  flex: 1;
  min-width: 0;
  min-height: 0;
  padding: 0 12px;
  font-size: 0.85rem;
  line-height: 1.45;
}
.onb-composer-inline-row > .composer-textarea:focus,
.onb-composer-inline-row > .input:focus,
.onb-composer-inline-row > .textarea:focus,
.onb-composer-inline-row > textarea:focus,
.onb-composer-inline-row > input:focus,
.onb-composer-inline-row > .onb-composer-input:focus {
  border: none;
  box-shadow: none;
  outline: none;
}

.onb-composer-send,
.pill-composer-action {
  flex-shrink: 0;
  /* Sized to its own padding so the nested button reads at the capsule-standard
     ~28px height. `align-self: center` is load-bearing — the parent pill
     uses `align-items: stretch`, which would otherwise force the button to
     match the textarea height once the composer grows past one line. Without
     this override the Send button stretches to a tall rectangle as the user
     types into line 2+. Center (not flex-end / flex-start) keeps the button
     vertically centered in the wrapper at every line count — at 1 line it's
     visually centered in the ~36px pill; at 3 lines it stays centered in the
     ~70px rounded rect.
     margin: 5px is load-bearing. With a 28px-tall button + 5+5 = 38px
     margin-box, the button exactly fills the pill's single-line content
     height (var(--input-height) = 38px) — align-self:center adds zero
     centering offset, so the visible gap from button to pill inner edge is
     a uniform 5px on top, bottom, and trailing sides. Drops to 4px and the
     1px center offset gives top gap = 5px but right gap = 4px (visibly
     uneven). Multi-line states (composer grown past 1 row) get extra
     vertical centering space; the trailing gap stays 5px regardless.
     padding: trailing gets a larger value than leading so the label has
     visible breathing room from the capsule's trailing edge (matches the
     additional vertical padding the button carries). Height is unchanged —
     the shorthand keeps vertical at calc(6px + offset). */
  align-self: center;
  margin: 4px;
  height: 24px;
  box-sizing: border-box;
  border-radius: 999px;
  padding: 0 14px;
  font-family: var(--font-ui);
  font-size: 12.5px;
  font-weight: var(--fw-medium);
  line-height: 1;
  min-height: 0;
}
.onb-composer-row {
  display: flex;
  gap: 6px;
  justify-content: center;
}

.onb-step2-meta {
  flex: 1;
  margin-top: 16px;
  font-size: 0.78rem;
  color: var(--text-muted);
}

/* Add-topic menu — sits between the Step 2 card list and the meta line.
   Lists Step 1 buckets the user did not pick; tapping one POSTs to
   /api/onboarding/cards/add and the new card auto-expands. */
.onb-add-topic-wrap {
  position: relative;
  display: flex;
  flex-direction: column;
  margin: 8px 0 4px;
}
.onb-add-topic-toggle {
  align-self: flex-start;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  padding: 4px 10px;
  font-family: var(--font-ui);
  font-size: 0.85rem;
  color: var(--text-secondary);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  transition: background 120ms, color 120ms, border-color 120ms;
}
.onb-add-topic-toggle:hover:not([disabled]) {
  background: var(--bg-hover);
  color: var(--text-primary);
}
.onb-add-topic-toggle[disabled] { opacity: 0.5; cursor: not-allowed; }
.onb-add-topic-toggle.open { color: var(--text-primary); }
.onb-add-topic-icon { font-weight: var(--fw-semibold); }
.onb-add-topic-caret { font-size: 0.7rem; }
.onb-add-topic-panel {
  margin-top: 6px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-card);
  padding: 4px;
  display: flex;
  flex-direction: column;
  gap: 1px;
  max-height: 280px;
  overflow-y: auto;
}
.onb-add-topic-header {
  padding: 6px 10px 4px;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-muted);
}
.onb-add-topic-row {
  display: flex;
  align-items: center;
  gap: 8px;
  height: 32px;
  padding: 0 8px;
  background: transparent;
  border: none;
  border-radius: var(--radius-pill);
  cursor: pointer;
  font-family: var(--font-ui);
  font-size: 0.85rem;
  color: var(--text-primary);
  text-align: left;
}
.onb-add-topic-row:hover:not([disabled]) { background: var(--bg-hover); }
.onb-add-topic-row[disabled] { opacity: 0.5; cursor: not-allowed; }
.onb-add-topic-emoji {
  display: inline-flex;
  width: 18px;
  justify-content: center;
  flex-shrink: 0;
}
.onb-add-topic-label {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ── Step 3 (Core preview) ── */

/* Step 2 → Step 3 transition animations. Step 3 chrome (title, subtitle,
   section cards) flips in immediately when the user clicks Continue on
   Step 2, while /api/onboarding/finalize runs in the background. The
   skeleton bodies pulse until the real markdown lands; section bodies
   then fade in (driven by .onb-fade-in being added in JS). */
@keyframes onb-fade-up {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes onb-fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes onb-skeleton-pulse {
  0%, 100% { opacity: 0.4; }
  50%      { opacity: 0.7; }
}

.onb-step3 > .onboarding-title { animation: onb-fade-up 320ms ease both; }
.onb-step3 > .onb-subtle        { animation: onb-fade-up 320ms 60ms ease both; }

/* Section cards stagger in — :nth-child offsets each by ~80ms so the
   cascade reads as motion rather than a single block reveal. */
.onb-step3 .onb-section-card { animation: onb-fade-up 320ms ease both; }
.onb-step3 .onb-section-card:nth-child(1) { animation-delay: 120ms; }
.onb-step3 .onb-section-card:nth-child(2) { animation-delay: 200ms; }
.onb-step3 .onb-section-card:nth-child(3) { animation-delay: 280ms; }
.onb-step3 .onb-section-card:nth-child(4) { animation-delay: 360ms; }
.onb-step3 .onb-section-card:nth-child(5) { animation-delay: 440ms; }

/* Body content fades in once the real data arrives. JS tags filled section
   bodies with .onb-fade-in; skeleton bodies use the pulse animation below. */
.onb-section-body.onb-fade-in { animation: onb-fade-in 320ms ease both; }

/* Skeleton body inside a loading section card — fixed height, soft pulse.
   Uses color-mix on the primary text token so it adapts to light/dark. */
.onb-section-body--skeleton {
  min-height: 32px;
  margin-top: 6px;
  border-radius: var(--radius-sm);
  background: linear-gradient(90deg,
    color-mix(in srgb, var(--text-primary) 10%, transparent),
    color-mix(in srgb, var(--text-primary) 18%, transparent),
    color-mix(in srgb, var(--text-primary) 10%, transparent));
  animation: onb-skeleton-pulse 1400ms ease-in-out infinite;
}

/* Inline retry row when finalize errors during the skeleton phase. */
.onb-step3-retry-row {
  display: flex;
  justify-content: flex-end;
  margin-top: 8px;
}

/* ── Step 3 vignette card (flag: ONBOARDING_VIGNETTE_ENABLED) ─────────────── */
/* A single narrative card with a hook title + 2-5 sentence body. Replaces
   the section accordion as the default Step 3 surface. Goes through view →
   refine state transitions in onboarding.js. */
.onb-step3-vignette-wrap > .onboarding-title { animation: onb-fade-up 320ms ease both; }
.onb-step3-vignette-wrap > .onb-subtle        { animation: onb-fade-up 320ms 60ms ease both; }
.onb-step3-vignette-wrap .onb-vignette-card   { animation: onb-fade-up 320ms 120ms ease both; }

.onb-vignette-card {
  padding: 24px 28px;
  margin: 20px 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-md, var(--radius-sm));
  background: var(--bg-base);
  display: flex;
  flex-direction: column;
  gap: 12px;
  transition: opacity 180ms ease;
}
.onb-vignette-card--dim {
  opacity: 0.55;
}
.onb-vignette-card--error {
  border-color: color-mix(in srgb, var(--text-primary) 18%, transparent);
}
.onb-vignette-title-row {
  display: flex;
  align-items: center;
  gap: 10px;
}
.onb-vignette-bullet {
  font-size: 0.95rem;
  color: var(--text-muted);
  line-height: 1;
}
.onb-vignette-title {
  margin: 0;
  font-size: 0.92rem;
  font-weight: var(--fw-semibold);
  color: var(--text-muted);
  letter-spacing: 0.02em;
}
.onb-vignette-body {
  margin: 0;
  font-size: 1.02rem;
  line-height: 1.6;
  color: var(--text-primary);
  white-space: pre-wrap;
}

/* Skeleton state — three pulsing bars stand in for the title + body lines
   so the layout doesn't reflow when the real prose arrives. */
.onb-vignette-card--skeleton .onb-vignette-title-skel,
.onb-vignette-card--skeleton .onb-vignette-body-skel {
  height: 12px;
  border-radius: var(--radius-sm);
  background: linear-gradient(90deg,
    color-mix(in srgb, var(--text-primary) 10%, transparent),
    color-mix(in srgb, var(--text-primary) 18%, transparent),
    color-mix(in srgb, var(--text-primary) 10%, transparent));
  animation: onb-skeleton-pulse 1400ms ease-in-out infinite;
}
.onb-vignette-card--skeleton .onb-vignette-title-skel { width: 40%; }
.onb-vignette-card--skeleton .onb-vignette-body-skel  { height: 14px; }
.onb-vignette-card--skeleton .onb-vignette-body-skel--short { width: 70%; }

/* Refine composer — textarea + helper line beneath the dimmed vignette. */
.onb-vignette-correction {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin: 10px 0 14px;
}
.onb-vignette-correction-input {
  width: 100%;
  resize: vertical;
  font: inherit;
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-base);
  color: var(--text-primary);
  line-height: 1.5;
}
.onb-vignette-correction-input:focus-visible {
  outline: 2px solid var(--accent, var(--text-primary));
  outline-offset: 2px;
}


.onb-core-sections {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 8px 0 12px;
}
.onb-section-card {
  padding: 14px 18px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-base);
}
/* Labeled rule between the filled-section group and the collapsed empty
   group. Hidden when either group is empty (controlled in JS). */
.onb-section-divider {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 6px 0 2px;
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-muted);
  font-weight: var(--fw-semibold);
}
.onb-section-divider::before,
.onb-section-divider::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--border);
}

/* Title row used by every section card in read mode — title on the leading
   edge, Chat-to-refine button pinned to the trailing edge. Body (when the
   section is filled) renders below this row. */
.onb-section-title-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
.onb-section-title-row .onb-section-title {
  margin: 0;
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.onb-section-title-row .onb-section-refine-btn {
  flex-shrink: 0;
}

/* Strict-accordion toggle affordance — the whole title row is the hit-target
   for opening / closing a section card. Cursor is the only treatment on the
   already-open card (where the click is a no-op); collapsed rows still get
   the standard pointer. */
.onb-section-title-row--toggle {
  cursor: pointer;
  user-select: none;
}
.onb-section-card--open .onb-section-title-row--toggle {
  cursor: default;
}
.onb-section-title-row--toggle:focus-visible {
  outline: 2px solid var(--accent, var(--text-primary));
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}
.onb-section-chevron {
  display: inline-block;
  flex-shrink: 0;
  width: 12px;
  font-size: 0.7rem;
  line-height: 1;
  color: var(--text-muted);
  transition: transform 160ms ease;
  transform: rotate(0deg);
}
.onb-section-chevron--open {
  transform: rotate(90deg);
}

/* Collapsed-card teaser — single-line preview of the section body, truncated
   with an ellipsis. Empty-state teaser is muted further. */
.onb-section-teaser {
  margin-top: 4px;
  font-size: 0.8rem;
  line-height: 1.4;
  color: var(--text-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.onb-section-teaser--empty {
  color: var(--text-muted);
  font-style: italic;
}

/* Empty / placeholder-only section: same title-row layout, just tighter
   padding (no body below) and muted title color. */
.onb-section-card--empty {
  padding: 8px 12px;
}
.onb-section-card--empty .onb-section-title {
  color: var(--text-secondary);
}
.onb-section-title {
  margin: 0 0 6px;
  font-size: 0.92rem;
  font-weight: var(--fw-semibold);
  color: var(--text-primary);
}
.onb-section-body {
  margin-top: 6px;
  font-size: 0.85rem;
  line-height: 1.5;
  color: var(--text-primary);
}
.onb-section-body p { margin: 4px 0; }
.onb-section-body ul { margin: 4px 0; padding-left: 20px; }
.onb-section-body li { margin: 2px 0; }
.onb-saving { font-size: 0.78rem; color: var(--text-muted); font-style: italic; }

/* Step 3 per-section refine — chat to refine button (in title row) plus
   chat / preview swap-out. Mirrors the wiki.js identity-section-refine
   pattern but inlined into the onboarding section card. */
.onb-section-refine-btn {
  font-size: 0.78rem;
  transition: background var(--transition), color var(--transition),
              border-color var(--transition), border-radius 160ms ease,
              opacity var(--transition);
}
/* Capsule shape on interactive states — hover, keyboard-focus, mid-click. */
.onb-section-refine-btn:hover:not(:disabled),
.onb-section-refine-btn:focus-visible:not(:disabled),
.onb-section-refine-btn:active:not(:disabled) {
  border-radius: 999px;
}
.onb-section-refine {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.onb-section-refine-label {
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-muted);
  font-weight: var(--fw-semibold);
  margin-top: 4px;
}
.onb-section-refine-label--muted { color: var(--text-muted); opacity: 0.8; }
.onb-section-body--original { opacity: 0.6; }

.onb-step3-ctas {
  display: flex;
  gap: 10px;
  margin-top: 32px;
  padding-top: 22px;
  border-top: 1px solid var(--border);
  flex-wrap: wrap;
  justify-content: flex-end;
}
/* Done button on Step 3 borrows the .btn-ghost hover chrome as its resting
   state so it reads as a real choice next to the primary CTA — without it
   the ghost button looks like inert text. Hover still nudges color via the
   base .btn-ghost:hover rule (no override needed). */
.onb-step3-ctas .onb-step3-done {
  background: var(--bg-hover);
  color: var(--text-primary);
  border-color: var(--border);
}

/* ── Step 3a (facet picker) ── */

.onb-suggestion-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px;
  margin: 8px 0 4px;
}
.onb-suggestion-card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  text-align: left;
  padding: 12px 14px;
  background: var(--bg-base);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text-primary);
  font-family: var(--font-ui);
  cursor: pointer;
  gap: 4px;
  transition: border-color 120ms, background 120ms;
}
.onb-suggestion-card:hover { background: var(--bg-hover); border-color: var(--accent-blue); }
.onb-suggestion-card.custom {
  border-style: dashed;
}
.onb-suggestion-title {
  font-size: 0.92rem;
  font-weight: var(--fw-semibold);
}
.onb-suggestion-desc {
  font-size: 0.78rem;
  color: var(--text-muted);
  line-height: 1.4;
}

/* ── Facet preview modal form ── */

.onb-facet-preview-body {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.onb-form-row {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.onb-form-label {
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-muted);
}
.onb-form-input,
.onb-form-textarea,
.onb-form-color {
  background: var(--bg-base);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text-primary);
  font-family: var(--font-ui);
  font-size: 0.88rem;
  padding: 8px 10px;
  box-sizing: border-box;
  width: 100%;
}
.onb-form-textarea { min-height: 140px; resize: vertical; line-height: 1.5; }
.onb-form-color { padding: 2px; height: 40px; cursor: pointer; }
.onb-form-input:focus,
.onb-form-textarea:focus { outline: none; border-color: var(--accent-blue); }

@media (max-width: 599px) {
  #onboarding-overlay .onboarding-card.onboarding-card-v2 { max-width: 100%; }
  .onb-suggestion-grid { grid-template-columns: 1fr; }
  /* Stack the Step 3 CTAs vertically — uniform width, uniform gaps. Visual
     order is reflowed via flex `order`: primary first (thumb-accessible),
     Done in the middle, Start over (destructive) demoted to the bottom.
     DOM order stays unchanged so desktop layout is unaffected. */
  .onb-step3-ctas {
    flex-direction: column;
    align-items: stretch;
    gap: 10px;
  }
  .onb-step3-ctas .btn {
    flex: 1 1 auto;
    width: 100%;
    margin-top: 0;
  }
  .onb-step3-ctas .btn-primary { order: 0; }
  .onb-step3-ctas .btn-ghost   { order: 1; }
  .onb-step3-ctas .btn-danger  { order: 2; }
  /* Desktop's leading-edge spacer is unneeded in the vertical stack. */
  .onb-step3-ctas .onb-spacer { display: none; }
}

/* ─── Core switcher strip ────────────────────────────────────────────────────
   Horizontal chip row rendered in the wiki rail header. One chip per Core
   (max 3). Each chip carries a trailing star that marks/sets the default
   Core. The "Add Core" CTA lives in the New Facet row below the strip. */

.core-switcher-strip {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 8px;
  flex-wrap: nowrap;
  overflow-x: auto;
  scrollbar-width: none;
}
.core-switcher-strip::-webkit-scrollbar { display: none; }

.core-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 8px 3px 4px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--border);
  background: var(--bg-card);
  color: var(--text-primary);
  font-family: var(--font-ui);
  font-size: 0.75rem;
  font-weight: var(--fw-medium);
  cursor: pointer;
  transition: border-color var(--transition), background var(--transition);
  white-space: nowrap;
  flex-shrink: 0;
}
.core-chip:hover:not(:disabled):not(.core-chip-active) {
  background: var(--bg-hover);
  border-color: var(--text-secondary);
}
.core-chip:disabled { opacity: 0.5; cursor: not-allowed; }

.core-chip-active {
  border-color: var(--accent-blue);
  box-shadow: 0 0 0 1px var(--accent-blue);
  cursor: default;
}

.core-chip-avatar {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  object-fit: cover;
  flex-shrink: 0;
}

.core-chip-initial {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--bg-hover);
  color: var(--text-secondary);
  font-size: 0.65rem;
  font-weight: var(--fw-semibold);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.core-chip-name {
  max-width: 72px;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Trailing star on each core chip — hollow ☆ marks a non-default Core
   (click to set as default), filled ★ marks the current default. Rendered
   as a <span role="button"> because the chip itself is a <button> and
   nested buttons are invalid HTML. */
.core-chip-star {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  margin-left: 2px;
  font-size: 0.85rem;
  line-height: 1;
  color: var(--text-secondary);
  cursor: pointer;
  user-select: none;
  transition: color var(--transition), transform var(--transition);
}
.core-chip-star:hover { transform: scale(1.15); }
.core-chip-star:focus-visible {
  outline: 1px solid var(--accent-blue);
  outline-offset: 1px;
  border-radius: 2px;
}
.core-chip-star-active {
  color: #f5b400;
  cursor: default;
}
.core-chip-star-active:hover { transform: none; }

/* New-Core modal tab bar */
.core-modal-tabs {
  display: flex;
  gap: 2px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 2px;
}
.core-modal-tab {
  padding: 6px 12px;
  border: none;
  border-bottom: 2px solid transparent;
  background: transparent;
  color: var(--text-secondary);
  font-family: var(--font-ui);
  font-size: 0.82rem;
  cursor: pointer;
  transition: color var(--transition), border-color var(--transition);
  margin-bottom: -1px;
}
.core-modal-tab:hover { color: var(--text-primary); }
.core-modal-tab--active {
  color: var(--text-primary);
  border-bottom-color: var(--accent-blue);
  font-weight: var(--fw-medium);
}

/* ─── Discover inline member picker (Variant B) ──────────────────────────────
   Chip row and picker container live inside the discover overlay panel —
   no new stacking context, no z-index collision with the modal system. */
.discover-stage-chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
  padding: 6px 0;
}

.discover-stage-picker {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm, 6px);
  padding: 10px;
  margin-top: 6px;
  max-height: 280px;
  overflow-y: auto;
  background: var(--surface-bg, var(--bg-card));
}

/* ─── Discover overlay: picker-open mode ──────────────────────────────────────
   When the inline member picker is open, collapse the facet header + hide
   non-composer sections, drop the outer content scroll, and make the picker
   fill the available vertical space. Only the card grid scrolls — single
   scroll surface, no nested scrollbars. */
.discover-overlay-panel.picker-open .discover-overlay-header { display: none; }
.discover-overlay-panel.picker-open .discover-overlay-content { overflow: hidden; min-height: 0; }
.discover-overlay-panel.picker-open .discover-overlay-section { display: none; }
.discover-overlay-panel.picker-open .discover-stage-picker {
  flex: 1 1 auto;
  min-height: 0;
  max-height: none;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  border: 0;
  padding: 0;
  margin-top: 0;
  background: transparent;
}
.discover-overlay-panel.picker-open .discover-stage-picker-list-region {
  min-height: 0;
}
.discover-overlay-panel.picker-open .add-voice-list {
  max-height: none;
  height: auto;
  overflow: visible;
  grid-auto-rows: min-content;
}

/* "Done" state — solid, filled neutral. Replaces the dashed-placeholder look
   so the button reads as a commit action rather than an empty slot. */
.add-voice-button.is-done {
  border-style: solid;
  border-color: var(--border);
  background: var(--bg-elevated);
  color: var(--text-primary);
}
.add-voice-button.is-done:hover {
  border-color: var(--accent-blue);
  color: var(--accent-blue);
}

/* Cards at cap that are not yet staged are non-interactive and dimmed. */
.add-voice-card.is-cap-disabled {
  opacity: 0.4;
  pointer-events: none;
  cursor: not-allowed;
}

.add-voice-cap-hint {
  font-size: 0.75rem;
  color: var(--text-muted);
  margin-bottom: 6px;
  padding: 4px 8px;
  border-radius: var(--radius-sm, 6px);
  background: var(--bg-elevated);
}
