/* ============================================================================
 * vega-shell.css — Vega-specific shell styles
 *
 * The @mach33/ui package ships shell.css with the base layout primitives
 * (.m33-app grid, .m33-panel-left, .m33-panel-right, .m33-user, etc.).
 * THIS file is the Vega-specific layer on top — rail widths, chevrons,
 * scrollbars, modals, search bar, chat-message scoping, footer pills.
 *
 * Served from public/m33-static/ via the /m33 mount (framework-server.js
 * line 122). Link tag injected by lib/vega-shell-extras.js headExtras().
 *
 * If you're adding a new style:
 *   - One-off, scoped to one element → inline style="..." is fine
 *   - Repeated 2+ times, OR needs :hover/:focus/media-queries → put it here
 *   - Dynamic (depends on state) → keep the imperative cssText / classList
 *     toggle in JS, but add the class definition here
 * ========================================================================= */

/* ── Compact mode ──────────────────────────────────────────────────────────
 * When ?host=<known> or ?compact=1 (iframe embed), hide standalone shell
 * chrome so the chat panel fills the iframe cleanly. */
html[data-compact="1"], html[data-compact="1"] body { background: transparent !important; }
html[data-compact="1"] .m33-app { grid-template-columns: 0 1fr 0 !important; }
html[data-compact="1"] .m33-app.m33-left-collapsed { grid-template-columns: 0 1fr 0 !important; }
html[data-compact="1"] .m33-app.m33-right-collapsed { grid-template-columns: 0 1fr 0 !important; }
html[data-compact="1"] .m33-app > nav,
html[data-compact="1"] .m33-app > aside,
html[data-compact="1"] .m33-app > header,
html[data-compact="1"] .m33-rail-toggle,
html[data-compact="1"] .m33-rail-chev { display: none !important; }

/* ── Rail widths + footer row height (override @mach33/ui defaults) ───
 * Columns:
 *   Left  : 240px expanded / 56px collapsed (navigation rail)
 *   Right : 294px (team-chat rail — 30% reduction from the original
 *           420px per Brant's call; chat panel was too wide)
 * Rows:
 *   Header: 56px (package default — kept)
 *   Center: 1fr  (package default — kept)
 *   Footer: 64px (was 32px; Vega's status bar holds LLM chips + 36px
 *           roster avatars + env+SHA+fabric, which need real vertical
 *           room. Below 64px the contents overflow the grid row and
 *           get clipped at the viewport bottom — user reported
 *           "contents are 90% outside the footer"). */
.m33-app {
  grid-template-columns: 240px 1fr var(--m33-right-w, 294px) !important;
  grid-template-rows: 56px 1fr 64px !important;
}
.m33-app.m33-left-collapsed {
  grid-template-columns: 56px 1fr var(--m33-right-w, 294px) !important;
  grid-template-rows: 56px 1fr 64px !important;
}
.m33-app.m33-right-collapsed {
  grid-template-columns: 240px 1fr 0 !important;
  grid-template-rows: 56px 1fr 64px !important;
}
.m33-app.m33-left-collapsed.m33-right-collapsed {
  grid-template-columns: 56px 1fr 0 !important;
  grid-template-rows: 56px 1fr 64px !important;
}

/* Rail-chevron positioning vars — STARTING values only.
 * installRailChevrons() (lib/vega-shell-extras.js ~line 1675) writes the
 * live rail width into these on every layout / collapse via
 * style.setProperty, so the chevrons slide with the rail edge.
 * NO !important — that would beat the dynamic JS write and pin the
 * chevron at 240px even when the rail collapses to 56px. */
:root { --m33-rail-chev-left: 240px; --m33-rail-chev-right: 294px; }
/* Control-group chrome — ONE knob for EVERY group-container border: the
 * header Views/Relay/Profile boxes, the footer status pills, and the
 * centre-panel header pills. Now that the per-agent header underline carries
 * the colour, these go neutral grey (matched to the search bar) to cut the
 * colour overload. Change these two values to re-tint every group at once.
 * (operator 2026-07-24) */
:root { --m33-group-border: rgba(255,255,255,0.30); --m33-group-ring: transparent; }

/* ── Sidebar collapse chevrons ────────────────────────────────────────────
 * Default-styled <button> was a sub-pixel sliver that no one noticed.
 * Pill-shaped, semi-transparent at rest, full opacity on hover. */
.m33-rail-chevron {
  position: fixed; top: 50%; transform: translateY(-50%);
  width: 22px; height: 44px; padding: 0;
  background: var(--m33-panel, #1a1d2c);
  border: 1px solid var(--m33-border, rgba(255,255,255,0.18));
  color: var(--m33-text, #e1e4ed);
  border-radius: 0 8px 8px 0;
  cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  opacity: 0.55;
  transition: opacity .12s, background .12s, transform .18s;
  z-index: 100;
  box-shadow: 0 4px 14px rgba(0,0,0,0.30);
}
.m33-rail-chevron:hover { opacity: 1; background: rgba(99,102,241,0.18); }
.m33-rail-chevron-left  { left: var(--m33-rail-chev-left, 240px); }
.m33-rail-chevron-right { right: var(--m33-rail-chev-right, 294px); border-radius: 8px 0 0 8px; }
.m33-rail-chevron-right svg { transform: scaleX(-1); }
.m33-rail-chevron.m33-flip svg { transform: scaleX(-1); }
.m33-rail-chevron-right.m33-flip svg { transform: none; }

/* ── App footer ──────────────────────────────────────────────────────────
 * Single full-width row at the bottom of the page, mirroring the header.
 * The @mach33/ui shell template already provides the right DOM:
 *   <footer class="m33-panel m33-footer" id="m33-footer">
 *     <div class="m33-footer-left">   …LLM status…           </div>
 *     <div class="m33-footer-center"> …team-presence roster… </div>
 *     <div class="m33-footer-right">  …env + SHA + fabric…   </div>
 *   </footer>
 * vega-shell-extras populates the three slots on boot.
 *
 * Two overrides on top of the package CSS:
 *   1. The agent skin (every Vega page) hides .m33-footer-left and
 *      .m33-footer-right via `visibility:hidden`. We always want them
 *      shown — re-enable here.
 *   2. Make the footer the same visual weight as the header: nudge
 *      the height up slightly, give footer-center a brighter color
 *      (the roster avatars want full opacity, not the muted footer
 *      default), and align the slots horizontally with consistent gaps. */
body[data-skin="agent"] .m33-footer-left,
body[data-skin="agent"] .m33-footer-right { visibility: visible !important; }

#m33-footer {
  /* Real status-bar height — generous enough that the avatars look
   * intentional and the LLM chips have presence (was 48px which the
   * user called "cramped to short"). Items inside scale up too via
   * the scoped overrides below. */
  min-height: 64px;
  padding: 10px 20px;
  font-size: 12px;
  background: var(--m33-bg, #0d0f14);
  border-top: 1px solid rgba(255,255,255,0.10);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.03);
}
/* Footer-scoped avatar sizing — chat-panel rail stays at 28px; in
 * the global footer they shrink to 24px so the TEAM pill reads as
 * dense and small, matching the LLM + BUILD pills' visual weight. */
#m33-footer .m33-roster-avatar { width: 24px; height: 24px; }
#m33-footer div.m33-roster-avatar { font-size: 9px; }
#m33-footer .m33-presence-dot { width: 7px; height: 7px; }

/* Relay tier-1 header — smaller MEMBERS avatars (22px) so the pill
 * reads as compact in the new sticky/blurred header layout. */
.m33-tier1-header .m33-roster-avatar { width: 22px; height: 22px; }
.m33-tier1-header div.m33-roster-avatar { font-size: 9px; }
.m33-tier1-header .m33-presence-dot { width: 7px; height: 7px; }

/* Kill the 20px padding the @mach33/ui shell.css drops at the top of
 * the center main panel — that gap sat the Relay chat header below
 * the global app header by an extra 20px ("MASSIVE gap" the user
 * called out 2026-06-21). The Relay surface owns its own header
 * spacing now via .m33-tier1-header, so this padding is dead weight. */
#m33-panel-center { padding-top: 0 !important; }

/* The Relay header is now position:absolute on top of the surface so
 * the chat scrolls UNDER it (same overlay behavior as the composer at
 * the bottom). Anchor against the surface; the messages container's
 * inline padding-top:76px clears the overlap, mask softens the edge. */
.m33-agent-surface { position: relative; }
#m33-footer .m33-footer-left,
#m33-footer .m33-footer-right {
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--m33-text-muted, rgba(255,255,255,0.55));
}
#m33-footer .m33-footer-center {
  display: flex;
  align-items: center;
  gap: 4px;
  flex: 1;
  justify-content: center;
  /* Center slot is reserved for full-color roster avatars, not muted
   * text — clear the framework's color override. */
  color: var(--m33-text, #e1e4ed);
}
/* The five footer groups read as ONE centered cluster with tight, even gaps
 * — not spread edge-to-edge (operator: "gaps are too large … center the
 * collective 5 groups"). Override the base space-between + the flex:1 centre
 * slot that flung the zones to the edges. Agent skin only. */
/* Bookend to the header's double-line: a SINGLE agent-colour rule above the
 * footer, so the app is framed top and bottom in the house colour. */
body[data-skin="agent"] #m33-footer {
  justify-content: center;
  gap: 8px;
  border-top: 1px solid var(--m33-agent-accent, rgba(255,255,255,0.10)) !important;
}
body[data-skin="agent"] #m33-footer .m33-footer-center { flex: 0 1 auto; }
body[data-skin="agent"] #m33-footer .m33-footer-left,
body[data-skin="agent"] #m33-footer .m33-footer-right { gap: 8px; }

/* Launcher tile wordmark — the NAME is the prominent line; the descriptor
 * is a small colour-carrying label beneath it. (operator: name/descriptor
 * size & type were reversed; the descriptor carries the agent's house
 * colour, set inline per tile in headerExtras.) Descriptor stays muted for
 * locked tiles ("No access"), which get no inline colour. */
.m33-launcher-meta .m33-launcher-app {
  font-size: 13px; font-weight: 600; color: var(--m33-text, #e1e4ed);
  text-transform: none; letter-spacing: normal;
}
.m33-launcher-meta .m33-launcher-skin {
  font-size: 11px; font-weight: 400; text-transform: uppercase;
  letter-spacing: 0.06em; color: var(--m33-text-muted, rgba(255,255,255,0.55));
}
/* Labeled group containers — each slot wraps its content in a
 * .vega-footer-group with a .vega-footer-label prefix. Same min-height
 * across all three so the LLM / TEAM / BUILD pills read as a row of
 * matched chips. */
/* Shared base pill recipe — used by both the global app footer
 * (.vega-footer-group) and the Relay chat-panel header
 * (.vega-header-group). Same look on both so the top and bottom of
 * the app read as the same visual language. */
.vega-footer-group,
.vega-header-group {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px 12px;
  background: rgba(255,255,255,0.025);
  border: 1px solid var(--m33-group-border);
  border-radius: 10px;
  /* Locked height — keeps each pill in a row visually aligned. min-height
   * let the TEAM pill grow 2px because the presence dot has bottom:-1px
   * which bled past the avatar. height + visible overflow keeps the
   * dot showing while pinning the pill at 36px exactly. */
  height: 36px;
  box-sizing: border-box;
  overflow: visible;
}
/* Footer pills are a touch taller — host the 24px roster avatars
 * comfortably. */
.vega-footer-group { height: 40px; }

.vega-footer-label,
.vega-header-label {
  font-size: 9px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: rgba(255,255,255,0.45);
  padding-right: 10px;
  margin-right: 0;
  border-right: 1px solid rgba(255,255,255,0.08);
  white-space: nowrap;
  flex: 0 0 auto;
}

/* LLM pill content lives inside footer-left; pill-style not needed
 * anymore since the footer itself is the container. Just style the
 * dot + label. */
.vega-llm-dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: #7dffaf;
  box-shadow: 0 0 4px rgba(125,255,175,0.6);
  flex: 0 0 auto;
  transition: background 200ms;
}
.vega-llm-label {
  font-size: 11px;
  letter-spacing: 0.02em;
  color: rgba(255,255,255,0.85);
  cursor: pointer;
}
.vega-fabric-stats {
  font-size: 9px;
  opacity: 0.55;
  letter-spacing: 0.01em;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  white-space: nowrap;
}
/* ── Roster avatar nodes (used in both the channel-rail header + the
 *    global footer pill via ChannelRailView.syncRosterDOM) ───────────── */
.m33-roster-node {
  position: relative;
  display: inline-block;
}
/* #145 — the per-avatar Page (🔔) button is ALWAYS visible and clickable: it is
 * its own explicit control (a hover-reveal read as "paging is gone"). Clicking
 * the 🔔 sends a page; clicking the avatar only opens the DM. */
.m33-roster-page {
  opacity: 0.9;
  pointer-events: auto;
  transition: opacity 120ms ease, transform 120ms ease;
}
.m33-roster-node:hover .m33-roster-page,
.m33-roster-page:hover,
.m33-roster-page:focus {
  opacity: 1;
  transform: scale(1.12);
}
.m33-roster-avatar {
  width: 28px; height: 28px;
  border-radius: 50%;
  display: block;
  object-fit: cover;
  background: rgba(255,255,255,0.10);
  transition: opacity 200ms, box-shadow 200ms;
}
/* When the avatar is the initials-fallback <div> (no avatar_url), it
 * needs flex centering for the letters; <img> just uses object-fit. */
div.m33-roster-avatar {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 10px;
  font-weight: 600;
}
.m33-presence-dot {
  position: absolute;
  bottom: -1px; right: -1px;
  width: 8px; height: 8px;
  border-radius: 50%;
  border: 1.5px solid var(--m33-bg, #0d0f14);
  transition: background 200ms;
}

/* ── Scrollbars ────────────────────────────────────────────────────────────
 * Browser-default scrollbars on dark UIs read as harsh light stripes. */
*::-webkit-scrollbar { width: 6px; height: 6px; }
*::-webkit-scrollbar-thumb {
  background: rgba(255,255,255,0.10);
  border-radius: 3px;
}
*::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,0.22); }
*::-webkit-scrollbar-track { background: transparent; }
* { scrollbar-width: thin; scrollbar-color: rgba(255,255,255,0.10) transparent; }

/* ── Patton agent skin overrides ──────────────────────────────────────────
 * Bump chat-meta visibility on the Patton agent skin so author labels
 * (PATTEN / user name) stand out. Vega defaults to 10px / muted;
 * Patton gets 11.5px, slightly less muted, and the author name a
 * vivid accent so the eye lands on it. Scoped to data-app so Vega's
 * chat stays as-is. */
body[data-app="patton"][data-skin="agent"] .m33-chat-meta {
  font-size: 11.5px;
  letter-spacing: 0.08em;
  color: rgba(255, 255, 255, 0.72);
}
body[data-app="patton"][data-skin="agent"] .m33-chat-author {
  font-weight: 700;
  color: #b8c0ff;
}
body[data-app="patton"][data-skin="agent"] .m33-chat-row.m33-from-user .m33-chat-author {
  color: #ffd9a8;
}
body[data-app="patton"][data-skin="agent"] .m33-chat-time {
  opacity: 0.85;
  font-weight: 500;
}

/* ── Page transition flash guard ──────────────────────────────────────────
 * Hide body content until the overlay is shown opaque on the new page.
 * The overlay element lives at the end of <body>; this style keeps the
 * intervening flash out of the user's view. Removed by the body-end script
 * once the overlay has taken over. */
html[data-m33-transitioning="1"] body > *:not(.m33-transition) { visibility: hidden; }
html[data-m33-transitioning="1"] body { background: #000; }

/* ── Modal size variants ──────────────────────────────────────────────────
 * Override the package's 540px default when openModal() is called with
 * opts.size. The body still scrolls on overflow; the FRAME is the part
 * that's fixed-sized. */
.m33-modal[data-m33-size="large"] {
  max-width: 1100px;
  max-height: calc(100vh - 64px);
}
.m33-modal[data-m33-size="fixed"] {
  /* Admin Settings: don't let content shifts (switching tabs, expanding
   * tables) resize the whole modal. Width and height are clamped within
   * the viewport so small screens don't overflow, but on a desktop the
   * modal lands at the same size every time. */
  width: min(1200px, calc(100vw - 48px));
  max-width: min(1200px, calc(100vw - 48px));
  height: min(800px, calc(100vh - 64px));
  max-height: min(800px, calc(100vh - 64px));
}
.m33-modal[data-m33-size="fixed"] .m33-modal-body {
  flex: 1 1 auto;
  min-height: 0; /* allow inner scroll instead of pushing the modal taller */
}

/* ── Global search bar ────────────────────────────────────────────────── */
.m33-global-search {
  position: relative;
  display: inline-flex;
  align-items: center;
  margin: 0 4px;
  z-index: 200;
}
/* Centred in the gap between the title and the session/views box: as the
 * header's middle flex child (hoistSearch places it there), auto side
 * margins absorb the free space evenly, floating the bar mid-gap. Natural
 * width is preserved so the results popup still anchors under the input. */
.m33-global-search.m33-search-centered { margin-left: auto; margin-right: auto; }
.m33-search-input-wrap {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  background: rgba(255,255,255,0.05);
  border: 1px solid rgba(255,255,255,0.30);
  border-radius: 6px;
  padding: 0 8px;
  height: 26px;
  width: 300px;             /* larger + FIXED — no grow-on-focus */
  transition: border-color 200ms ease, background 200ms ease;
}
.m33-search-input-wrap:focus-within {
  /* width stays 300px — the bar is a fixed length now; only the accent
   * border + wash change on focus. */
  border-color: rgba(125,138,255,0.55);
  background: rgba(125,138,255,0.08);
}
.m33-search-icon {
  flex-shrink: 0;
  opacity: 0.45;
}
.m33-search-input-wrap:focus-within .m33-search-icon { opacity: 0.7; }
.m33-search-input {
  flex: 1;
  min-width: 0;
  background: transparent;
  border: none;
  outline: none;
  color: #e8eaff;
  font: 500 11px/1.4 -apple-system, system-ui, sans-serif;
  letter-spacing: 0.01em;
  padding: 0;
}
.m33-search-input::placeholder { color: rgba(255,255,255,0.30); }
.m33-search-clear {
  flex-shrink: 0;
  background: transparent;
  border: none;
  color: rgba(255,255,255,0.4);
  font: 500 14px/1 sans-serif;
  cursor: pointer;
  padding: 0 1px;
  transition: color 120ms;
}
.m33-search-clear:hover { color: rgba(255,255,255,0.8); }
.m33-search-kbd {
  flex-shrink: 0;
  font: 500 9px/1 ui-monospace, SFMono-Regular, Menlo, monospace;
  color: rgba(255,255,255,0.25);
  border: 1px solid rgba(255,255,255,0.12);
  border-radius: 3px;
  padding: 1px 3px;
}
.m33-search-input-wrap:focus-within .m33-search-kbd { display: none; }

/* Dropdown results panel */
.m33-search-results {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  width: 360px;
  max-height: 380px;
  overflow-y: auto;
  background: rgba(14,16,28,0.95);
  border: 1px solid rgba(255,255,255,0.12);
  border-radius: 10px;
  box-shadow: 0 8px 32px rgba(0,0,0,0.6), 0 0 0 1px rgba(0,0,0,0.3);
  backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);
  padding: 4px;
  z-index: 210;
}
.m33-search-result {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 10px;
  border-radius: 6px;
  cursor: pointer;
  transition: background 100ms;
}
.m33-search-result:hover,
.m33-search-result.m33-active {
  background: rgba(125,138,255,0.14);
}
.m33-search-result-glyph {
  flex-shrink: 0;
  width: 22px; height: 22px;
  border-radius: 5px;
  display: flex; align-items: center; justify-content: center;
  font: 600 11px/1 -apple-system, system-ui, sans-serif;
  color: #fff;
  background: rgba(255,255,255,0.08);
}
.m33-search-result-text {
  flex: 1; min-width: 0;
}
.m33-search-result-label {
  font: 500 13px/1.3 -apple-system, system-ui, sans-serif;
  color: #e8eaff;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.m33-search-result-sub {
  font: 400 11px/1.3 -apple-system, system-ui, sans-serif;
  color: rgba(255,255,255,0.4);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.m33-search-result-score {
  flex-shrink: 0;
  font: 400 10px/1 ui-monospace, SFMono-Regular, monospace;
  color: rgba(255,255,255,0.2);
}
.m33-search-empty {
  padding: 16px;
  text-align: center;
  color: rgba(255,255,255,0.35);
  font: 400 12px/1.4 -apple-system, system-ui, sans-serif;
}

/* Surface highlighting: canvas cards, chat rows, table rows */
.m33-card.m33-search-dimmed {
  opacity: 0.12 !important;
  pointer-events: none;
  transition: opacity 300ms ease;
}
.m33-card.m33-search-highlighted {
  box-shadow: 0 0 0 2px rgba(125,138,255,0.55), 0 0 16px rgba(125,138,255,0.15) !important;
  z-index: 1;
  transition: box-shadow 300ms ease;
}
.m33-chat-row.m33-search-dimmed {
  opacity: 0.15;
  transition: opacity 300ms ease;
}

/* ── Animations ───────────────────────────────────────────────────────── */
@keyframes m33-sandbox-pulse {
  0%, 100% { border-color: rgba(240,200,80,0.85); box-shadow: 0 24px 64px rgba(0,0,0,0.55), 0 0 12px rgba(240,200,80,0.25); }
  50%      { border-color: rgba(240,200,80,1);    box-shadow: 0 24px 64px rgba(0,0,0,0.55), 0 0 24px rgba(240,200,80,0.45); }
}
@keyframes m33spin { to { transform: rotate(360deg); } }

/* ── Thinking-bubble animation ────────────────────────────────────────────
 * Two cases:
 *  1. .m33-chat-msg.m33-thinking-empty — assigned to an empty assistant
 *     bubble while we wait for the first delta. Shows three pulsing
 *     dots so the user has a visible signal that Vega is working.
 *  2. .m33-chat-msg-thinking — applied during a tool round-trip
 *     ("Searching…"). Adds an italic + soft pulse so the placeholder
 *     reads as in-progress rather than as the final answer. */
/* One pseudo-element renders all three dots: the element background is
 * the MIDDLE dot; the left/right dots are box-shadows. Each dot brightens
 * (and swells +1px via shadow spread) in sequence — left → middle →
 * right — so the indicator reads as a live typing wave, not the old
 * all-at-once blink. color-mix keeps it themed off currentColor. */
.m33-chat-msg.m33-thinking-empty:empty::after {
  content: '';
  display: inline-block;
  vertical-align: middle;
  margin: 8px 16px 8px 14px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background-color: color-mix(in srgb, currentColor 30%, transparent);
  box-shadow: -11px 0 0 0 color-mix(in srgb, currentColor 30%, transparent),
               11px 0 0 0 color-mix(in srgb, currentColor 30%, transparent);
  animation: m33-thinking-wave 1.2s ease-in-out infinite;
}
@keyframes m33-thinking-wave {
  0%, 100% {
    background-color: color-mix(in srgb, currentColor 30%, transparent);
    box-shadow: -11px 0 0 1px color-mix(in srgb, currentColor 90%, transparent),
                 11px 0 0 0   color-mix(in srgb, currentColor 30%, transparent);
  }
  33% {
    background-color: color-mix(in srgb, currentColor 90%, transparent);
    box-shadow: -11px 0 0 0 color-mix(in srgb, currentColor 30%, transparent),
                 11px 0 0 0 color-mix(in srgb, currentColor 30%, transparent);
  }
  66% {
    background-color: color-mix(in srgb, currentColor 30%, transparent);
    box-shadow: -11px 0 0 0   color-mix(in srgb, currentColor 30%, transparent),
                 11px 0 0 1px color-mix(in srgb, currentColor 90%, transparent);
  }
}
/* Long waits shouldn't strobe for motion-sensitive users — hold the dots
 * steady at a calm mid-opacity instead. */
@media (prefers-reduced-motion: reduce) {
  .m33-chat-msg.m33-thinking-empty:empty::after { animation: none; opacity: 0.55; }
}
.m33-chat-msg-thinking {
  font-style: italic;
  opacity: 0.7;
  animation: m33-thinking-pulse 1.6s ease-in-out infinite;
}
@keyframes m33-thinking-pulse {
  0%, 100% { opacity: 0.45; }
  50%      { opacity: 0.85; }
}

/* ── Markdown rendering inside assistant bubbles ──────────────────────────
 * mdToHtmlEscaped produces <h1>..<h4>, <strong>, <em>, <code>, <ul>,
 * <ol>, <blockquote>, <p>. Without scoped styles those inherit the
 * surrounding chat font and end up too large / not enough spaced.
 * Tighten them to the bubble's reading scale. */
.m33-chat-msg h1, .m33-chat-msg h2, .m33-chat-msg h3, .m33-chat-msg h4 {
  margin: 12px 0 4px;
  font-weight: 600;
  line-height: 1.25;
}
.m33-chat-msg h1 { font-size: 1.25em; }
.m33-chat-msg h2 { font-size: 1.15em; }
.m33-chat-msg h3 { font-size: 1.05em; }
.m33-chat-msg h4 { font-size: 1em; opacity: 0.85; }
.m33-chat-msg h1:first-child, .m33-chat-msg h2:first-child,
.m33-chat-msg h3:first-child, .m33-chat-msg h4:first-child { margin-top: 0; }
.m33-chat-msg p { margin: 6px 0; }
.m33-chat-msg p:first-child { margin-top: 0; }
.m33-chat-msg p:last-child  { margin-bottom: 0; }
.m33-chat-msg ul, .m33-chat-msg ol { margin: 6px 0 6px 18px; padding: 0; }
.m33-chat-msg li { margin: 2px 0; }
.m33-chat-msg code {
  background: rgba(255,255,255,0.08);
  border-radius: 3px;
  padding: 1px 4px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.9em;
}
.m33-chat-msg strong { font-weight: 600; }
.m33-chat-msg blockquote {
  margin: 6px 0;
  padding: 2px 10px;
  border-left: 2px solid rgba(255,255,255,0.25);
  opacity: 0.85;
}

/* ─────────────────────────────────────────────────────────────
 * Modality picker + mute (Relay header — UI scaffolding)
 *
 * Three pills (Text / Audio / Video), exactly one active at a time.
 * Mute button appears only when modality is Audio or Video.
 * State-only today; actual call wiring lands when /api/chat/stream
 * routes through the Proto's turn() in a later phase.
 * ───────────────────────────────────────────────────────────── */
.m33-modality-group { gap: 8px; }
.m33-modality-btn {
  height: 24px;
  padding: 0 10px;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.01em;
  background: transparent;
  border: 1px solid rgba(255,255,255,0.10);
  border-radius: 6px;
  color: rgba(255,255,255,0.55);
  cursor: pointer;
  transition: background 120ms, border-color 120ms, color 120ms;
  font-family: inherit;
}
.m33-modality-btn:hover:not(.m33-active):not(:disabled) {
  border-color: rgba(255,255,255,0.20);
  color: rgba(255,255,255,0.85);
}
.m33-modality-btn.m33-active {
  background: rgba(99,179,237,0.12);
  border-color: rgba(99,179,237,0.35);
  color: rgba(160,200,240,0.95);
}
.m33-modality-btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

.m33-mute-btn {
  height: 28px;
  padding: 0 12px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: transparent;
  border: 1px solid rgba(255,255,255,0.12);
  border-radius: 8px;
  color: rgba(255,255,255,0.80);
  font-size: 11px;
  font-weight: 500;
  cursor: pointer;
  transition: background 120ms, border-color 120ms, color 120ms;
  font-family: inherit;
}
.m33-mute-btn:hover:not([data-muted="1"]):not(:disabled) {
  border-color: rgba(255,255,255,0.25);
  color: rgba(255,255,255,1);
}
.m33-mute-btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
  color: rgba(255,255,255,0.4);
}
.m33-mute-btn[data-muted="1"] {
  background: rgba(220,80,80,0.15);
  border-color: rgba(220,80,80,0.45);
  color: rgba(255,160,160,0.95);
}
.m33-mute-btn[data-muted="1"]:hover {
  background: rgba(220,80,80,0.20);
  border-color: rgba(220,80,80,0.60);
}
.m33-mute-icon { font-size: 13px; line-height: 1; }

/* ─────────────────────────────────────────────────────────────
 * Channel pill — split (label-toggle + ▾ arrow) + Tasks pill inside CHANNEL
 *
 * The channel pill is now two adjacent button zones rendered as one pill:
 *   .m33-tc-chan-toggle  — click name flips chat↔tasks
 *   .m33-tc-chan-arrow   — click ▾ opens channel/DM picker
 * Tasks pill (.m33-tier1-btn-tasks) lives INSIDE the CHANNEL group
 * alongside the channel pill — they are mutually-exclusive centre-panel views.
 * ───────────────────────────────────────────────────────────── */
.m33-tc-chan-split {
  /* Pill chrome moves to the wrap; inner buttons are flush. Mirrors the
   * existing .m33-tc-chan look (transparent + 14px radius active state). */
  border-radius: 14px;
  background: rgba(99,102,241,0.18);
  border: 1px solid var(--m33-accent, #6366f1);
}
.m33-tc-chan-split .m33-tc-chan-toggle:hover,
.m33-tc-chan-split .m33-tc-chan-arrow:hover {
  background: rgba(255,255,255,0.06);
}
.m33-tc-chan-split .m33-tc-chan-arrow:hover { opacity: 1; }

/* Tasks pill inside the CHANNEL group — match the modality pills' size + shape
 * so the two centre-panel pickers (channel chat / tasks) read as siblings. */
.m33-tier1-btn-tasks {
  height: 24px;
  padding: 0 10px;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.01em;
  background: transparent;
  border: 1px solid rgba(255,255,255,0.10);
  border-radius: 6px;
  color: rgba(255,255,255,0.55);
  cursor: pointer;
  font-family: inherit;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  transition: background 120ms, border-color 120ms, color 120ms;
}
.m33-tier1-btn-tasks:hover:not(.m33-active) {
  border-color: rgba(255,255,255,0.20);
  color: rgba(255,255,255,0.85);
}
.m33-tier1-btn-tasks.m33-active {
  background: rgba(99,179,237,0.12);
  border-color: rgba(99,179,237,0.35);
  color: rgba(160,200,240,0.95);
}

/* When tier-1 is "tasks", de-emphasise the channel pill so the user can
 * see at a glance which view is active. Keep it clickable — clicking the
 * channel label flips back to chat. */
.m33-agent-surface[data-tier1="tasks"] .m33-tc-chan-split {
  background: rgba(255,255,255,0.04);
  border-color: rgba(255,255,255,0.10);
}

/* ============================================================
 * Shared agent header — 3-box chrome (views · Relay · profile)
 * A "project/views" box, a "Relay" box (implanted agent), and a profile box,
 * all sharing the same blue rounded-rect outline; plus a header bottom edge
 * line and a soft chat-stream fade under the header and composer. Shared
 * across all agent skins; only box contents differ.
 * ============================================================ */
body[data-skin="agent"] .m33-header {
  /* Agent signature strip — a thin DOUBLE rule in the running agent's house
   * colour (--m33-agent-accent, set in the shell head from lib/agent-marks).
   * 4px renders `double` as two hairlines with a clear gap: whose room you
   * are in, at a glance. Falls back to the neutral edge line when unset. */
  border-bottom: 4px double var(--m33-agent-accent, rgba(255, 255, 255, 0.1)) !important;
}
/* The thin brand-suffix half (Research / Communications / Operations …)
 * carries the same house colour as the signature strip: "Vega Research"
 * reads green, "Relay Communications" reads indigo — the wordmark tied to
 * the room. Agent skin only; login/application chrome keeps its own colour. */
body[data-skin="agent"] .m33-app-name-thin { color: var(--m33-agent-tint, var(--m33-agent-accent, inherit)); }
body[data-skin="agent"] .nw-research-box .nw-grp-label,
body[data-skin="agent"] .nw-relay-box .nw-grp-label {
  font: 600 10px/1 inherit; color: rgba(255,255,255,0.5);
  text-transform: uppercase; letter-spacing: 0.06em;
  padding: 0 8px 0 4px; align-self: center; white-space: nowrap;
}
body[data-skin="agent"] .nw-relay-box { margin-left: 8px; }
/* The Relay label matches its neighbours (Chat/Canvas/Graph buttons):
 * same family, same 12px, same muted color — mixed case, label not heading. */
body[data-skin="agent"] .nw-relay-box .nw-grp-label {
  /* Longhands, not the `font:` shorthand — `inherit` is not a valid
   * family inside the shorthand, so browsers DROP the whole declaration
   * silently (measured live: label rendered 14px while Graph is 12px). */
  text-transform: none; letter-spacing: 0;
  font-size: 12px; font-weight: 400; line-height: 1;
  color: var(--m33-text-muted);
}

/* One header height. The Relay group's icon buttons (13px SVGs) and the
 * search pill rendered shorter than the text-button groups — pin all three
 * to the same scale so the header reads as one row of equals. */
body[data-skin="agent"] .nw-research-box,
body[data-skin="agent"] .nw-relay-box { min-height: 34px; align-items: center; }
body[data-skin="agent"] .nw-relay-box .m33-mode-btn {
  display: inline-flex; align-items: center; justify-content: center;
  padding-top: 7px; padding-bottom: 7px; min-height: 27px; box-sizing: border-box;
}
/* In the agent header the search reads as a SIBLING of the control-group
 * pills (nw boxes / .m33-mode-toggle): same height, 8px corners, card fill,
 * and the shared --m33-group-border. (operator 2026-07-24: height/corners/
 * shading didn't match.) Login (application skin) keeps the flat field look. */
body[data-skin="agent"] .m33-search-input-wrap {
  height: 34px;
  border-radius: 8px;
  background: var(--m33-card, #22253a);
  border-color: var(--m33-group-border);
}

/* The user's own chat bubble carries the AGENT colour (like the header
 * underline), not the global indigo — Vega green, Relay indigo, Patton amber…
 * Overrides the framework's .m33-chat-msg.m33-from-user{background:accent}.
 * Falls back to --m33-accent where no agent colour is injected. */
body[data-skin="agent"] .m33-chat-msg.m33-from-user {
  background: var(--m33-agent-accent, var(--m33-accent));
}

/* Primary actions (Send, Assistant, Create…) carry the agent colour, not the
 * global indigo; hover lightens it. And the composer prompt boxes take the
 * agent colour on focus. */
body[data-skin="agent"] .m33-primary-btn { background: var(--m33-agent-accent, var(--m33-accent)); }
body[data-skin="agent"] .m33-primary-btn:hover { background: color-mix(in oklab, var(--m33-agent-accent, var(--m33-accent)) 85%, #fff); }
body[data-skin="agent"] .m33-chat-form input:focus { border-color: var(--m33-agent-accent, var(--m33-accent)); }

/* Project/views group, Relay group, and profile group share the same blue
 * outline + rounded-rect shape (the Relay box keeps the shape, signalling the
 * implanted agent by content rather than a different border). */
body[data-skin="agent"] .nw-research-box,
body[data-skin="agent"] .nw-relay-box,
body[data-skin="agent"] .nw-profile-box {
  border: 1px solid var(--m33-group-border) !important;
  box-shadow: 0 0 0 1px var(--m33-group-ring);
}
body[data-skin="agent"] .nw-profile-box {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 3px 10px 3px 6px; border-radius: 8px;
}

/* Newton: the project dropdown IS the context control, so hide the older
 * session switcher. Vega/Patton reuse that switcher, moved into the views box
 * (so it stays visible there) — hence this hide stays Newton-only. */
body[data-app="newton"] .m33-ideation-switcher { display: none !important; }

/* Context dropdown — replaces the static "Research" label. Newton shows the
 * current project; Vega/Patton mount the session switcher into the slot. */
body[data-skin="agent"] .nw-proj-dd { position: relative; display: inline-flex; align-items: center; }
body[data-skin="agent"] .nw-proj-dd-btn {
  display: inline-flex; align-items: center; gap: 5px;
  background: none; border: none; cursor: pointer;
  font: 600 11px/1 inherit; color: rgba(255,255,255,0.8);
  padding: 0 8px 0 6px; white-space: nowrap;
}
body[data-skin="agent"] .nw-proj-dd-btn:hover { color: #fff; }
body[data-skin="agent"] .nw-proj-dd-chev { font-size: 9px; opacity: 0.55; }
/* Fixed positioning so the menu escapes the fixed-height header's clip;
 * coordinates are set from the button's rect when it opens. */
body[data-skin="agent"] .nw-proj-dd-menu {
  position: fixed; min-width: 240px;
  background: #1a1d2c; border: 1px solid rgba(255,255,255,0.12);
  border-radius: 10px; box-shadow: 0 16px 48px rgba(0,0,0,0.5);
  padding: 6px; z-index: 4000;
}
body[data-skin="agent"] .nw-proj-dd-item {
  display: block; width: 100%; text-align: left; box-sizing: border-box;
  padding: 8px 10px; border-radius: 7px; background: none; border: none;
  cursor: pointer; font: inherit; color: #dfe1f1; text-decoration: none;
}
body[data-skin="agent"] .nw-proj-dd-item:hover { background: rgba(125,138,255,0.12); }
body[data-skin="agent"] .nw-pdd-name { display: block; font: 600 12px/1.3 inherit; color: #fff; }
body[data-skin="agent"] .nw-pdd-sub { display: block; font: 11px/1.3 inherit; color: rgba(255,255,255,0.45); }
body[data-skin="agent"] .nw-pdd-all { border-top: 1px solid rgba(255,255,255,0.08); margin-top: 4px; padding-top: 8px; }

/* Vega/Patton mount the session switcher into the views-box slot. The switcher
 * is an absolutely-positioned standalone banner by default — neutralise that
 * inside the slot so it flows inline within the group box. */
body[data-skin="agent"] .nw-session-slot .m33-ideation-switcher {
  position: static !important; inset: auto !important; transform: none !important;
  margin: 0 !important; display: inline-flex !important;
}

/* Chat stream fades under the header and composer (like Newton). */
body[data-skin="agent"] .m33-chat-stream {
  padding-top: 40px;
  padding-bottom: 40px;
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 40px, #000 calc(100% - 40px), transparent 100%);
          mask-image: linear-gradient(to bottom, transparent 0, #000 40px, #000 calc(100% - 40px), transparent 100%);
}

/* Team posture swaps panels (Relay → centre slot, Vega → right slot), so
 * the right chevron collapses the Vega side panel — it stays visible.
 * The very subtle right-rail resizer: a 5px grab strip on the panel's
 * left edge; invisible at rest, a hairline accent on hover/drag. */
.m33-right-resizer {
  position: fixed; top: 56px; bottom: 64px;
  right: var(--m33-rail-chev-right, 294px); width: 5px; margin-right: -2px;
  cursor: col-resize; z-index: 900; background: transparent;
}
.m33-right-resizer:hover, .m33-right-resizer.m33-dragging {
  background: linear-gradient(to right, transparent 1px, rgba(125,138,255,0.35) 2px, rgba(125,138,255,0.35) 3px, transparent 4px);
}
.m33-app.m33-right-collapsed ~ .m33-right-resizer, body[data-compact="1"] .m33-right-resizer { display: none; }

/* ── App fade-in ──────────────────────────────────────────────────────────
 * The shell eases in on load instead of popping — the closing half of the
 * login → boot → app transition ("when the agent is ready it fades back
 * in"). Cheap and universal: every page load gets the same 400ms ease,
 * which also softens ordinary navigations. */
@keyframes m33AppFadeIn { from { opacity: 0; } to { opacity: 1; } }
.m33-app { animation: m33AppFadeIn 400ms ease; }
@media (prefers-reduced-motion: reduce) { .m33-app { animation: none; } }

/* Icon-corner alerts on the Relay group (operator, 2026-07-21):
 * missed-chat count over the chat icon, and a pulsing amber dot over the
 * calendar icon when a live meeting expects the user. */
body[data-skin="agent"] .nw-relay-box .m33-mode-btn { position: relative; }
/* Corner badges OVERLAY the icon by ~25% (operator): anchored inside the
 * button so a quarter of the badge sits on the glyph's corner. */
body[data-skin="agent"] 
/* Calendar locked (no canCalendar grant): visible but inert — the click
 * handler blocks navigation, this just says so at a glance. */
.nw-relay-box .m33-mode-btn.m33-cal-locked { opacity: 0.35; cursor: not-allowed; }

/* Alerts bell badge — unacknowledged count, same corner-pill law as the
 * chat badge (red, ~25% overlay, 9+ cap done by the writer). */
.nw-relay-box .m33-alert-badge {
  position: absolute; top: -2px; right: -2px;
  min-width: 18px; height: 18px; box-sizing: border-box;
  padding: 0 4px; border-radius: 10px;
  background: #e2544a; color: #fff;
  border: 1.5px solid rgba(16,17,26,0.9);
  font-size: 11px; font-weight: 700; line-height: 15px; text-align: center;
}

/* ── Relay panel header redesign (operator, 2026-07-22) ─────────────────
 * The global header's grammar: fully rounded pill PERIMETERS in the
 * subtle blue; labels normal-case inside; modes are monochrome stroke
 * icons (active white, idle muted); mute is the warm mic-off that only
 * exists during audio/video; ☰/⤢ are borderless ghosts. */
.m33-tier1-header .vega-header-group {
  /* EXACT global-header recipe (nw-research/relay-box): same border,
   * same faint outer ring, same card fill, same 8px soft-round that
   * reads pill-like at this height, same 34px. One visual language. */
  border: 1px solid var(--m33-group-border);
  box-shadow: 0 0 0 1px var(--m33-group-ring);
  background: var(--m33-card, #22253a);
  border-radius: 8px;
  height: 34px; min-height: 34px;
}
.m33-tier1-header .vega-header-label {
  font-size: 12px; font-weight: 400; text-transform: none;
  letter-spacing: 0; color: var(--m33-text-muted, #9aa0b4); padding-right: 0;
}
.m33-tier1-header .m33-modality-btn,
.m33-tier1-header .m33-mute-btn {
  background: none; border: 0; padding: 2px; cursor: pointer; line-height: 0;
}
.m33-tier1-header .m33-modality-btn svg { stroke: #8a8fa3; }
.m33-tier1-header .m33-modality-btn.m33-active svg { stroke: #ffffff; }
.m33-tier1-header .m33-mute-btn svg { stroke: #f0a29c; }
.m33-tier1-header .m33-mute-btn[data-muted="1"] svg { stroke: #e2544a; }
.m33-tier1-header .m33-hdr-ghost {
  background: none; border: 0; color: #8a8fa3; cursor: pointer;
  font-size: 14px; line-height: 1; padding: 4px 6px; opacity: 0.85;
}
.m33-tier1-header .m33-hdr-ghost:hover { color: #d7d9e0; }

/* The active-channel chip inside the header pill goes NEUTRAL (operator,
 * 2026-07-22: "the blue highlight around the channel is not required") —
 * blue belongs to the group perimeter only. Soft white fill, no accent
 * border, matching the approved design's inner-content neutrality. */
.m33-tier1-header .m33-tc-chan-active {
  background: rgba(255,255,255,0.07) !important;
  border-color: transparent !important;
}

/* ── Relay-in-the-centre gets Vega's reading column (operator, 2026-07-22)
 * Team posture puts the Relay panel in the centre slot; its timeline and
 * composer take the SAME centered 760px column the Vega chat stream uses
 * (shell.css .m33-chat-stream recipe) so both centre experiences read
 * identically. Scoped to team posture — in the right rail the panel
 * stays edge-to-edge (a 294px rail needs no clamp). */
body[data-manifold="team"] #m33-panel-right .m33-tc-messages {
  padding-left: max(10px, calc((100% - 760px) / 2)) !important;
  padding-right: max(10px, calc((100% - 760px) / 2)) !important;
}
body[data-manifold="team"] #m33-panel-right .m33-tc-composer {
  /* The composer is an ABSOLUTE bottom bar with inline left:0;right:0;
   * margin:0 — margins can't centre it (inline wins) and shouldn't: the
   * blurred bar spans the panel. Centre its CONTENT instead. */
  align-items: center !important;
}
body[data-manifold="team"] #m33-panel-right .m33-tc-composer > * {
  width: 100%; max-width: 760px;
}
body[data-manifold="team"] #m33-panel-right .m33-tier1-header {
  /* The pill header follows the same reading column as the content
   * below it — Channel/Mode/Members align with the conversation
   * instead of clinging to the panel edges. */
  /* !important: the header ships inline padding:0 14px. */
  padding-left: max(14px, calc((100% - 760px) / 2)) !important;
  padding-right: max(14px, calc((100% - 760px) / 2)) !important;
}

/* EVERY footer pill wears the global blue recipe (operator,
 * 2026-07-22): LLMs, LQMS, Prompt, Team (Humans | Agents), Build —
 * the bottom of the app speaks the same language as the top. */
#m33-footer .vega-footer-group {
  border: 1px solid var(--m33-group-border);
  box-shadow: 0 0 0 1px var(--m33-group-ring);
  background: var(--m33-card, #22253a);
  border-radius: 8px;
}

/* Footer pills distribute EVENLY across the row (operator, 2026-07-22):
 * the three slot wrappers dissolve (display:contents) so every pill —
 * LLMs · LQMs · Prompt · Team · Build — is a direct flex item of the
 * footer's existing space-between row. */
#m33-footer .m33-footer-left,
#m33-footer .m33-footer-center,
#m33-footer .m33-footer-right { display: contents; }
