/* static/css/ranger.css
 * ------------------------------------------------------------------
 * The Ranger launcher system. Section 1 below (the dock) ships in
 * Task 9 of the conversations-finalize program; a later task (T13)
 * grows a second "stage" section here for the Ranger center-modal
 * surface, per docs/superpowers/specs/
 * 2026-08-13-conversations-finalize-design.md.
 *
 * Loaded from exactly ONE place -- templates/base.html, under a single
 * `{% if conv.inbox or conv.ranger %}` guard -- never from a per-surface
 * partial, so two flag-gated surfaces sharing this sheet (the dock here,
 * the stage later) can never double-load it. See base.html's own comment
 * at that guard, and templates/social/_conv_dock_launcher.html's header
 * comment for the dock markup this file styles.
 *
 * Tokens only: every color/space/radius/shadow/font/z-index value below
 * goes through a static/css/design-tokens.css custom property (with a
 * literal fallback matching that token's own current value -- the same
 * `var(--ag-token, fallback)` idiom templates/social/chat_widget.html and
 * templates/social/chat_search_page.html already use throughout their own
 * inline <style> blocks). Logical properties throughout (inset-inline-*,
 * inset-block-*, margin-inline-*) so this mirrors correctly in Arabic RTL
 * with no direction-specific rules. This file's own comments never spell
 * out the two-character comment-close sequence (asterisk immediately
 * followed by slash) inside their own prose -- a past incident in this
 * repo dropped an entire stylesheet exactly that way, by closing a
 * comment early in the middle of a sentence describing the rule.
 *
 * Acknowledged exception to "tokens only": five `rgba(255, 255, 255, N)`
 * white-overlay/tint literals below (the capsule border, .ag-dock__seg's
 * hover and focus-visible ring, the .ag-dock__div divider, and the
 * .ag-orb ring) are NOT routed through a custom property. Checked
 * design-tokens.css deliberately, not just skipped: it has no "overlay
 * white at N% opacity on a dark/gradient surface" token to consume --
 * every existing color token is a specific brand/semantic color, not a
 * translucent tint primitive. The sibling `.ag-pill:hover`/
 * `:focus-visible` rules this component replaces (chat_widget.html) use
 * the identical untokenized pattern for the same reason. Flagged here
 * explicitly rather than left silent.
 * ------------------------------------------------------------------ */

/* ==================================================================
   1. THE DOCK -- split-capsule launcher (Task 9 / spec section 3)
   ================================================================== */

.ag-dock,
.ag-dock *{ box-sizing:border-box; }

.ag-dock{
  position:fixed;
  inset-inline-end: 18px;
  inset-block-end: var(--dock-bottom, 18px);
  z-index: var(--ag-z-modal, 200);
  display:flex;
  align-items:center;
  gap: var(--ag-space-1, 4px);
  padding: var(--ag-space-1, 4px);
  background: var(--ag-gradient-brand, linear-gradient(135deg, #1E284A 0%, #2E74B8 55%, #F1C9AE 100%));
  border-radius: var(--ag-radius-full, 999px);
  border: solid 1px rgba(255, 255, 255, 0.16);
  box-shadow: var(--ag-shadow-xl, 0 24px 50px rgba(15, 23, 42, 0.16));
  font: var(--ag-font-size-base, 13px)/1.4 var(--ag-font-sans, "Poppins", system-ui, sans-serif);
  transition: var(--ag-transition-transform, transform 200ms ease), var(--ag-transition-opacity, opacity 150ms ease);
}

/* Immersive surfaces (reels, fullscreen globe) hide the dock entirely.
   Matches the `data-immersive-hide` attribute on #ag-dock's root element
   -- an attribute selector rather than a class selector so any future
   floating object can opt into the same immersive-mode behavior without
   also being an .ag-dock. */
body[data-immersive] [data-immersive-hide]{ display:none; }

/* Toggled by a later task's scroll listener (below 768px: hide on
   scroll-down, return on scroll-up/top/new-unread) and while the stage is
   open. Slides toward the edge the capsule is already anchored to
   (inset-block-end) -- translateY is safe here without a logical
   equivalent because RTL only mirrors the INLINE axis, never the
   vertical/block axis. */
.ag-dock--hide{
  transform: translateY(calc(100% + 24px));
  opacity:0;
  pointer-events:none;
}

/* Explicit force-size modifiers (DOM contract for later tasks) --
   independent of the viewport-driven sizing below, e.g. for a compact
   embedded context that can't rely on media queries alone. */
.ag-dock--md .ag-dock__seg{ width:40px; height:40px; }
.ag-dock--sm .ag-dock__seg{ width:36px; height:36px; }

/* ---- segments (Messages <a>, Ranger <button>) -------------------- */

.ag-dock__seg{
  position:relative;
  display:flex;
  align-items:center;
  justify-content:center;
  width:44px;
  height:44px;
  padding:0;
  border:0;
  border-radius: var(--ag-radius-full, 999px);
  background:transparent;
  color: var(--ag-color-text-on-primary, #fff);
  text-decoration:none;
  cursor:pointer;
  transition: var(--ag-transition-colors, background-color 150ms ease);
}
.ag-dock__seg:hover{ background: rgba(255, 255, 255, 0.14); }
.ag-dock__seg:focus-visible{
  outline:none;
  /* Plain white inset ring, not --ag-shadow-focus -- that token's blue
     tint reads poorly against this dark gradient. Mirrors the legacy
     .ag-pill:focus-visible ring this component replaces (chat_widget.html). */
  box-shadow: inset 0 0 0 2px rgba(255, 255, 255, 0.72);
}

/* Divider between the two segments -- only in the DOM when conv.ranger
   is also on (templates/social/_conv_dock_launcher.html). */
.ag-dock__div{
  align-self:center;
  width:1px;
  height:22px;
  background: rgba(255, 255, 255, 0.28);
}

/* Chat glyph -- crafted inline SVG (rounded speech bubble + three typing
   dots), never an emoji (renders inconsistently per OS beside the
   gradient orb). Path data lives in the partial; only presentation here. */
.ag-dock__chat{ width:20px; height:20px; }
.ag-dock__chat .bub{ fill: var(--ag-color-text-on-primary, #fff); }
.ag-dock__chat .d{ fill: var(--ag-color-brand-secondary, #1E284A); }

/* Unread indicator -- carries a digit (messages-axis count from
   static/js/ranger/dock.js's setBadge(), capped at "99+"), rendered only
   when conv.alerts is on and starts `hidden`; realtime.js's `unread.sync`
   wiring (messages axis, relayed through dock.js) shows/hides/updates it.
   Fix round 1: this started as a fixed 9x9px dot with no room for text --
   sized here like realtime.js's own #ag-pill-messages-count digit badge
   (flex-centered content, `min-width` rather than a fixed `width` so
   "99+" can grow past the single-digit resting size, small bold label
   type) instead. Three responsive tiers below shrink this alongside
   .ag-dock__seg/.ag-dock__chat/.ag-orb at the same two breakpoints, so
   the badge stays proportionate as the dock itself shrinks. */
.ag-dock__badge{
  position:absolute;
  inset-block-start:6px;
  inset-inline-end:6px;
  display:flex;
  align-items:center;
  justify-content:center;
  min-width:16px;
  height:16px;
  padding-inline: var(--ag-space-1, 4px);
  border-radius: var(--ag-radius-full, 999px);
  background: var(--ag-color-error, #dc2626);
  box-shadow: 0 0 0 2px var(--ag-color-brand-secondary, #1E284A);
  color: var(--ag-color-text-on-primary, #fff);
  font-size: var(--ag-font-size-xs, 10px);
  font-weight: var(--ag-font-weight-bold, 700);
  line-height:1;
}

/* ---- the Ranger orb ------------------------------------------------
   Reused as-is by the stage header in a later task (hence the --sm/--md
   size modifiers rather than a single fixed size). */
.ag-orb{
  --orb-size: 22px;
  display:inline-flex;
  align-items:center;
  justify-content:center;
  width: var(--orb-size);
  height: var(--orb-size);
  border-radius: var(--ag-radius-full, 999px);
  background: conic-gradient(
    from 0deg,
    var(--ag-color-brand-accent, #F1C9AE),
    var(--ag-color-brand-primary, #2E74B8),
    var(--ag-color-brand-secondary, #1E284A),
    var(--ag-color-brand-accent, #F1C9AE)
  );
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.4);
  color: var(--ag-color-text-on-primary, #fff);
  font-size: calc(var(--orb-size) * 0.5);
  line-height:1;
  /* static/css/animations.css defines @keyframes ag-spin and loads
     unconditionally on every page (templates/partials/_head_common.html)
     -- reused by name here rather than redefined. */
  animation: ag-spin 7s linear infinite;
}
.ag-orb--md{ --orb-size: 22px; }
.ag-orb--sm{ --orb-size: 16px; }

/* Belt-and-braces: static/css/animations.css already forces
   animation-duration:0.01ms on every element site-wide under reduced
   motion, but the orb's spin is explicitly called out in this task's own
   requirements, so it also gets its own explicit, self-documenting stop
   here rather than relying only on the global rule. */
@media (prefers-reduced-motion: reduce){
  .ag-orb{ animation:none; }
}

/* ---- tooltips ([data-tip], shown on hover/focus) ------------------- */

.ag-dock [data-tip]{ position:relative; }
.ag-dock [data-tip]::after{
  content: attr(data-tip);
  position:absolute;
  inset-block-end: calc(100% + 10px);
  inset-inline-start:0;
  inset-inline-end:0;
  width:max-content;
  max-width:180px;
  margin-inline:auto;
  padding: var(--ag-space-1, 4px) var(--ag-space-2, 8px);
  border-radius: var(--ag-radius-md, 8px);
  background: var(--ag-color-brand-secondary, #1E284A);
  color: var(--ag-color-text-on-primary, #fff);
  font-size: var(--ag-font-size-xs, 10px);
  font-weight: var(--ag-font-weight-medium, 500);
  line-height:1.3;
  text-align:center;
  box-shadow: var(--ag-shadow-md, 0 10px 22px rgba(24, 33, 51, 0.08));
  opacity:0;
  visibility:hidden;
  pointer-events:none;
  z-index: var(--ag-z-tooltip, 400);
  transition: var(--ag-transition-opacity, opacity 150ms ease);
}
.ag-dock [data-tip]:hover::after,
.ag-dock [data-tip]:focus-visible::after{
  opacity:1;
  visibility:visible;
}

/* ---- one-time intro popover ("Ranger lives here now") -------------
   Template-only in this task ([hidden] by default); a later task shows
   it once on first render after the legacy pills disappear and persists
   the dismissal to localStorage (`ag_dock_intro_v1`). [hidden] already
   gets display:none from the UA stylesheet -- no display rule needed
   here to hide it, only to style it for when a later task removes the
   attribute. */
.ag-dock__intro{
  position:absolute;
  inset-block-end: calc(100% + 14px);
  inset-inline-end:0;
  width:240px;
  max-width:78vw;
  padding: var(--ag-space-4, 16px);
  border-radius: var(--ag-radius-xl, 12px);
  background: var(--ag-color-bg-surface, #fff);
  color: var(--ag-color-text-body, #2A2A55);
  border: 1px solid var(--ag-color-border, #D9E1EE);
  box-shadow: var(--ag-shadow-xl, 0 24px 50px rgba(15, 23, 42, 0.16));
  font-size: var(--ag-font-size-sm, 12px);
  line-height:1.45;
  z-index: var(--ag-z-popover, 300);
}
.ag-dock__intro b{
  display:block;
  margin-block-end: var(--ag-space-1, 4px);
  color: var(--ag-color-text-heading, #1E284A);
  font-size: var(--ag-font-size-md, 14px);
}
.ag-dock__intro-ok{
  display:block;
  margin-block-start: var(--ag-space-3, 12px);
  margin-inline-start:auto;
  padding: var(--ag-space-1, 4px) var(--ag-space-3, 12px);
  border:0;
  border-radius: var(--ag-radius-full, 999px);
  background: var(--ag-color-brand-primary, #2E74B8);
  color: var(--ag-color-text-on-primary, #fff);
  font: inherit;
  font-weight: var(--ag-font-weight-bold, 600);
  cursor:pointer;
  transition: var(--ag-transition-colors, background-color 150ms ease);
}
.ag-dock__intro-ok:hover{ background: var(--ag-color-brand-primary-hover, #2563eb); }
.ag-dock__intro-ok:focus-visible{
  outline:none;
  box-shadow: var(--ag-shadow-focus, 0 0 0 4px rgba(46, 116, 184, 0.16));
}

/* ---- responsive segment sizing: 44px (>=1024px, default) / 40px
   (>=768px) / 36px (<768px). Desktop-first cascade (matches this app's
   own .ag-chat convention in chat_widget.html): base rule is the
   >=1024px size, and each max-width query below overrides it in turn,
   with the narrower query last so it wins at the smallest widths. ---- */
@media (max-width: 1023.98px){
  .ag-dock__seg{ width:40px; height:40px; }
  .ag-dock__chat{ width:18px; height:18px; }
  .ag-orb{ --orb-size: 20px; }
  .ag-dock__badge{ min-width:14px; height:14px; }
}
@media (max-width: 767.98px){
  .ag-dock__seg{ width:36px; height:36px; }
  .ag-dock__chat{ width:16px; height:16px; }
  .ag-orb{ --orb-size: 18px; }
  .ag-dock__badge{ min-width:12px; height:12px; }
}

/* ==================================================================
   2. THE STAGE -- center-modal Ranger surface (Task 13 / spec section 4)
   Markup: templates/social/_ranger_stage.html (that file's own header
   comment carries the full DOM contract). Tokens-only discipline continues
   from section 1 above with ZERO new untokenized-literal exceptions in this
   section -- every color below (including the veil's own tint/scrim and the
   listing-card price chip's photo scrim) resolves to an EXISTING design-
   tokens.css custom property at that token's OWN already-defined alpha,
   rather than a bespoke rgba(...) value invented to match the approved
   mockup's exact look. That is a deliberate, slightly-more-conservative
   choice than section 1's five acknowledged white-overlay exceptions above:
   this task's own brief states "design tokens only" without section 1's own
   softer framing, so where the approved mockup used a color with no token
   equivalent, this section reaches for the nearest EXISTING token instead
   of adding a new exception to this file's acknowledged list.
   ================================================================== */

.ag-stage-veil,
.ag-stage-veil *{ box-sizing:border-box; }

/* ---- veil + panel --------------------------------------------------- */

#ag-stage-veil{
  position: fixed;
  inset: 0;
  z-index: var(--ag-z-modal, 200);
  display: grid;
  place-items: center;
  padding: var(--ag-space-6, 24px);
  /* Both stops are EXISTING tokens at their own existing alpha (a soft
     brand-primary tint fading into the app's own overlay-scrim color) --
     see this section's own header note on why no bespoke alpha was added. */
  background: radial-gradient(720px 540px at 50% 44%, var(--ag-color-brand-primary-softer, rgba(46, 116, 184, 0.12)), var(--ag-color-bg-overlay, rgba(15, 23, 42, 0.5)) 62%);
  backdrop-filter: blur(9px) saturate(1.05);
  -webkit-backdrop-filter: blur(9px) saturate(1.05);
  opacity: 0;
  pointer-events: none;
  transition: var(--ag-transition-opacity, opacity 200ms ease);
}
/* Belt-and-braces: [hidden] already gets display:none from the UA
   stylesheet with higher specificity than `display:grid` above needs to
   beat, but this file's own established convention (section 1's
   .ag-dock__intro note) states it explicitly anyway. See templates/social/
   _ranger_stage.html's own header comment for why the veil itself is NOT
   [hidden] by default the way #ag-stage-drawer/#ag-stage-voicebar below
   are -- a later task's open/close needs this element in the render tree
   to transition opacity/transform at all. */
#ag-stage-veil[hidden]{ display: none; }
#ag-stage-veil.ag-stage-veil--open{
  opacity: 1;
  pointer-events: auto;
}

#ag-stage{
  position: relative;
  width: min(720px, 100vw - 32px);
  max-height: min(760px, 94vh);
  display: flex;
  flex-direction: column;
  background: var(--ag-color-bg-surface, #FFFFFF);
  border-radius: var(--ag-radius-modal, 16px);
  overflow: hidden;
  box-shadow: var(--ag-shadow-2xl, 0 30px 80px rgba(2, 8, 20, 0.35));
  font: var(--ag-font-size-base, 13px)/var(--ag-line-height-normal, 1.5) var(--ag-font-sans, "Poppins", system-ui, sans-serif);
  color: var(--ag-color-text-body, #2A2A55);
  transform: translateY(16px) scale(0.96);
  opacity: 0;
  transition: var(--ag-transition-transform, transform 240ms ease), var(--ag-transition-opacity, opacity 200ms ease);
}
/* translateY + scale, no logical-property concern: exactly like section 1's
   own .ag-dock--hide note explains, RTL only mirrors the INLINE axis, never
   the vertical/block one or a uniform scale -- this motion is safe as-is. */
#ag-stage-veil.ag-stage-veil--open #ag-stage{
  transform: translateY(0) scale(1);
  opacity: 1;
}

@media (prefers-reduced-motion: reduce){
  #ag-stage-veil,
  #ag-stage{ transition: opacity var(--ag-duration-normal, 150ms) ease; }
  #ag-stage,
  #ag-stage-veil.ag-stage-veil--open #ag-stage{ transform: none; }
}

/* ---- header ----------------------------------------------------------- */

.ag-stage__head{
  display: flex;
  align-items: center;
  gap: var(--ag-space-3, 12px);
  padding: var(--ag-space-4, 16px) var(--ag-space-5, 20px);
  border-block-end: 1px solid var(--ag-color-border-subtle, rgba(46, 116, 184, 0.12));
  background: var(--ag-gradient-brand-soft, linear-gradient(135deg, rgba(30,40,74,.18), rgba(46,116,184,.22), rgba(241,201,174,.22)));
  flex-shrink: 0;
}
.ag-stage__id{ min-width: 0; flex: 1; }
.ag-stage__title{
  margin: 0;
  display: flex;
  align-items: center;
  gap: var(--ag-space-2, 8px);
  font-size: var(--ag-font-size-lg, 15px);
  font-weight: var(--ag-font-weight-bold, 600);
  color: var(--ag-color-text-heading, #1E284A);
}
.ag-stage__tag{
  display: inline-flex;
  align-items: center;
  background: var(--ag-gradient-button, linear-gradient(145deg, #2563eb, #4f46e5));
  color: var(--ag-color-text-on-primary, #fff);
  border-radius: var(--ag-radius-full, 999px);
  padding: 2px var(--ag-space-2, 8px);
  font-size: var(--ag-font-size-xs, 10px);
  font-weight: var(--ag-font-weight-bold, 600);
  letter-spacing: var(--ag-letter-spacing-wide, .04em);
}
.ag-stage__status{
  margin: 2px 0 0;
  font-size: var(--ag-font-size-xs, 10px);
  color: var(--ag-color-text-muted, #6B7491);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ag-stage__status b{
  color: var(--ag-color-success, #059669);
  font-weight: var(--ag-font-weight-bold, 600);
}
.ag-stage__acts{ display: flex; gap: var(--ag-space-1, 4px); flex-shrink: 0; }

/* Shared small round icon-button -- header actions, drawer close. Distinct
   from section 1's .ag-dock__seg (that one sits on the dark brand-gradient
   dock capsule; this sits on the stage's light surface, so it needs its own
   light-surface color pairing rather than reusing that rule verbatim). */
.ag-iconbtn{
  width: 34px;
  height: 34px;
  border: 0;
  border-radius: var(--ag-radius-full, 999px);
  background: var(--ag-color-bg-surface-alt, #F9FAFD);
  color: var(--ag-color-text-body, #2A2A55);
  display: grid;
  place-items: center;
  cursor: pointer;
  transition: var(--ag-transition-colors, background-color 150ms ease, color 150ms ease);
}
.ag-iconbtn svg{ width: 16px; height: 16px; }
.ag-iconbtn:hover{ background: var(--ag-color-brand-primary-soft, #E3EDF9); color: var(--ag-color-brand-primary, #2E74B8); }
.ag-iconbtn:focus-visible{ outline: none; box-shadow: var(--ag-shadow-focus, 0 0 0 4px rgba(46, 116, 184, 0.16)); }

/* ---- body / hello state / suggestions --------------------------------- */

#ag-stage-body{
  flex: 1;
  overflow-y: auto;
  padding: var(--ag-space-5, 20px) var(--ag-space-5, 20px) var(--ag-space-2, 8px);
  display: flex;
  flex-direction: column;
  gap: var(--ag-space-1, 4px);
  background: var(--ag-color-bg-surface-alt, #F9FAFD);
  min-height: 320px;
}

.ag-stage-hello{ text-align: center; padding: var(--ag-space-6, 24px) var(--ag-space-3, 12px) var(--ag-space-2, 8px); }
.ag-stage-hello .ag-orb{ margin-inline: auto; margin-block-end: var(--ag-space-3, 12px); --orb-size: 56px; box-shadow: var(--ag-shadow-lg, 0 18px 36px rgba(18, 32, 38, 0.12)); }
.ag-stage-hello__title{ margin: 0 0 var(--ag-space-1, 4px); font-size: var(--ag-font-size-2xl, 19px); font-weight: var(--ag-font-weight-bold, 600); color: var(--ag-color-text-heading, #1E284A); }
.ag-stage-hello__sub{ margin: 0; font-size: var(--ag-font-size-sm, 12px); color: var(--ag-color-text-muted, #6B7491); }
/* Size modifier used only by the hello state's hero orb (DOM contract for
   later tasks, matching section 1's own --sm/--md pair). font-size scales
   with --orb-size via .ag-orb's own `calc(var(--orb-size) * .5)` rule --
   nothing to repeat here. */
.ag-orb--hero{ --orb-size: 56px; }

.ag-stage-sugg{
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--ag-space-2, 8px);
  padding: var(--ag-space-4, 16px) var(--ag-space-1, 4px) var(--ag-space-2, 8px);
}
@media (max-width: 620px){
  .ag-stage-sugg{ grid-template-columns: 1fr; }
}

.ag-stage-sugg__chip{
  display: flex;
  align-items: center;
  gap: var(--ag-space-2, 8px);
  text-align: start;
  border: 1px solid var(--ag-color-border, #D9E1EE);
  background: var(--ag-color-bg-surface, #fff);
  border-radius: var(--ag-radius-2xl, 14px);
  padding: var(--ag-space-3, 12px);
  cursor: pointer;
  font-family: inherit;
  transition: var(--ag-transition-all, all 150ms ease);
  box-shadow: var(--ag-shadow-xs, 0 1px 2px rgba(0, 0, 0, 0.04));
}
.ag-stage-sugg__chip:hover{
  border-color: var(--ag-color-brand-primary-border, rgba(46, 116, 184, 0.28));
  box-shadow: var(--ag-shadow-sm, 0 4px 15px rgba(15, 23, 42, 0.06));
  transform: translateY(-1px);
}
.ag-stage-sugg__chip:focus-visible{
  outline: none;
  box-shadow: var(--ag-shadow-focus, 0 0 0 4px rgba(46, 116, 184, 0.16));
}
/* Fix round 1 (Minor): the hover-lift transform on this chip had no
   reduced-motion override, unlike the identical translateY(...) hover-lift
   on .ag-stage-send and .ag-stage-lcard elsewhere in this section -- same
   pattern as those two: narrow the transitioned properties to non-motion
   ones (border-color/box-shadow stay fine under reduced motion) and force
   the hover transform off. */
@media (prefers-reduced-motion: reduce){
  .ag-stage-sugg__chip{ transition: border-color 150ms ease, box-shadow 150ms ease; }
  .ag-stage-sugg__chip:hover{ transform: none; }
}
.ag-stage-sugg__ic{
  width: 34px;
  height: 34px;
  flex-shrink: 0;
  border-radius: var(--ag-radius-lg, 10px);
  display: grid;
  place-items: center;
  font-size: var(--ag-font-size-md, 14px);
  background: var(--ag-color-brand-primary-soft, #E3EDF9);
}
.ag-stage-sugg__copy{ min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.ag-stage-sugg__copy b{ font-size: var(--ag-font-size-sm, 12px); color: var(--ag-color-text-heading, #1E284A); font-weight: var(--ag-font-weight-bold, 600); }
.ag-stage-sugg__copy span{
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--ag-font-size-xs, 10px);
  color: var(--ag-color-text-muted, #6B7491);
}

.ag-stage-sugg__ar{
  display: block;
  margin: var(--ag-space-1, 4px) auto var(--ag-space-3, 12px);
  border: 1px solid var(--ag-color-brand-primary-border, rgba(46, 116, 184, 0.28));
  background: var(--ag-color-bg-surface, #fff);
  color: var(--ag-color-brand-primary, #2E74B8);
  border-radius: var(--ag-radius-full, 999px);
  padding: var(--ag-space-2, 8px) var(--ag-space-4, 16px);
  font-size: var(--ag-font-size-sm, 12px);
  font-weight: var(--ag-font-weight-medium, 500);
  cursor: pointer;
  transition: var(--ag-transition-colors, background-color 150ms ease);
}
.ag-stage-sugg__ar:hover{ background: var(--ag-color-brand-primary-soft, #E3EDF9); }
.ag-stage-sugg__ar:focus-visible{ outline: none; box-shadow: var(--ag-shadow-focus, 0 0 0 4px rgba(46, 116, 184, 0.16)); }

/* ---- composer ----------------------------------------------------------- */

.ag-stage__composer{
  padding: var(--ag-space-3, 12px) var(--ag-space-4, 16px) var(--ag-space-2, 8px);
  border-block-start: 1px solid var(--ag-color-border-subtle, rgba(46, 116, 184, 0.12));
  background: var(--ag-color-bg-surface, #fff);
  flex-shrink: 0;
}

#ag-stage-ctx{
  display: inline-flex;
  align-items: center;
  gap: var(--ag-space-2, 8px);
  max-width: 100%;
  font-size: var(--ag-font-size-xs, 11px);
  font-weight: var(--ag-font-weight-medium, 500);
  color: var(--ag-color-text-body, #2A2A55);
  background: var(--ag-color-brand-primary-softer, rgba(46, 116, 184, 0.12));
  border: 1px solid var(--ag-color-brand-primary-border, rgba(46, 116, 184, 0.28));
  border-radius: var(--ag-radius-full, 999px);
  padding: var(--ag-space-1, 4px) var(--ag-space-1, 4px) var(--ag-space-1, 4px) var(--ag-space-2, 8px);
  margin-block-end: var(--ag-space-2, 8px);
}
#ag-stage-ctx[hidden]{ display: none; }
.ag-stage-ctx__thumb{ width: 22px; height: 22px; border-radius: var(--ag-radius-full, 999px); background-size: cover; background-position: center; flex-shrink: 0; }
.ag-stage-ctx__label{ min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ag-stage-ctx__clear{
  border: 0;
  background: none;
  cursor: pointer;
  color: var(--ag-color-text-muted, #6B7491);
  font-size: var(--ag-font-size-sm, 12px);
  padding: 0 var(--ag-space-1, 4px);
  line-height: 1;
  border-radius: var(--ag-radius-full, 999px);
}
.ag-stage-ctx__clear:focus-visible{ outline: none; box-shadow: var(--ag-shadow-focus, 0 0 0 4px rgba(46, 116, 184, 0.16)); }

.ag-stage-box{
  display: flex;
  align-items: flex-end;
  gap: var(--ag-space-2, 8px);
  background: var(--ag-color-bg-surface-alt, #F9FAFD);
  border: 1.5px solid transparent;
  border-radius: var(--ag-radius-4xl, 18px);
  padding: var(--ag-space-1, 4px) var(--ag-space-1, 4px) var(--ag-space-1, 4px) var(--ag-space-3, 12px);
  transition: var(--ag-transition-colors, background-color 150ms ease, border-color 150ms ease), var(--ag-transition-shadow, box-shadow 250ms ease);
}
.ag-stage-box:focus-within{
  border-color: var(--ag-color-brand-primary-border, rgba(46, 116, 184, 0.28));
  background: var(--ag-color-bg-surface, #fff);
  box-shadow: var(--ag-shadow-focus, 0 0 0 4px rgba(46, 116, 184, 0.16));
}

#ag-stage-ta{
  flex: 1;
  min-width: 0;
  border: 0;
  background: none;
  outline: none;
  resize: none;
  font: inherit;
  font-size: var(--ag-font-size-md, 14px);
  color: var(--ag-color-text-body, #2A2A55);
  padding: var(--ag-space-2, 8px) 0;
  max-height: 120px;
  line-height: var(--ag-line-height-normal, 1.5);
}
#ag-stage-ta::placeholder{ color: var(--ag-color-text-muted, #6B7491); }

.ag-stage-tbtn{
  width: 36px;
  height: 36px;
  flex-shrink: 0;
  border: 0;
  border-radius: var(--ag-radius-full, 999px);
  background: none;
  color: var(--ag-color-text-muted, #6B7491);
  display: grid;
  place-items: center;
  font-size: var(--ag-font-size-lg, 15px);
  cursor: pointer;
  transition: var(--ag-transition-colors, background-color 150ms ease, color 150ms ease);
}
.ag-stage-tbtn:hover{ background: var(--ag-color-brand-primary-soft, #E3EDF9); color: var(--ag-color-brand-primary, #2E74B8); }
.ag-stage-tbtn:focus-visible{ outline: none; box-shadow: var(--ag-shadow-focus, 0 0 0 4px rgba(46, 116, 184, 0.16)); }

.ag-stage-send{
  width: 38px;
  height: 38px;
  flex-shrink: 0;
  border: 0;
  border-radius: var(--ag-radius-full, 999px);
  background: var(--ag-gradient-button, linear-gradient(145deg, #2563eb, #4f46e5));
  color: var(--ag-color-text-on-primary, #fff);
  display: grid;
  place-items: center;
  font-size: var(--ag-font-size-lg, 15px);
  cursor: pointer;
  box-shadow: var(--ag-shadow-primary, 0 7px 20px rgba(37, 99, 235, 0.35));
  transition: var(--ag-transition-transform, transform 150ms ease);
}
.ag-stage-send:hover{ transform: translateY(-1px); }
.ag-stage-send:active{ transform: translateY(0); }
.ag-stage-send:focus-visible{ outline: none; box-shadow: var(--ag-shadow-focus, 0 0 0 4px rgba(46, 116, 184, 0.16)); }

@media (prefers-reduced-motion: reduce){
  .ag-stage-send{ transition: none; }
}

/* ---- footer ------------------------------------------------------------- */

.ag-stage__foot{
  display: flex;
  align-items: center;
  gap: var(--ag-space-2, 8px);
  padding: var(--ag-space-1, 4px) var(--ag-space-5, 20px) var(--ag-space-3, 12px);
  background: var(--ag-color-bg-surface, #fff);
  color: var(--ag-color-text-muted, #6B7491);
  font-size: var(--ag-font-size-xs, 10px);
  flex-wrap: wrap;
  flex-shrink: 0;
}
.ag-stage__sep{ opacity: .5; }
.ag-stage__foot-right{
  margin-inline-start: auto;
  display: inline-flex;
  align-items: center;
  gap: var(--ag-space-1, 4px);
}
.ag-stage-kbd{
  font-family: var(--ag-font-mono, "JetBrains Mono", "Fira Code", Consolas, monospace);
  font-size: var(--ag-font-size-xs, 10px);
  background: var(--ag-color-bg-surface-alt, #F9FAFD);
  border: 1px solid var(--ag-color-border-strong, #CBD5E1);
  border-radius: var(--ag-radius-sm, 6px);
  padding: 1px var(--ag-space-1, 4px);
}
.ag-stage-qchip{
  display: inline-flex;
  align-items: center;
  gap: var(--ag-space-1, 4px);
  font-size: var(--ag-font-size-xs, 10.5px);
  padding: 3px var(--ag-space-2, 8px);
  border-radius: var(--ag-radius-full, 999px);
  border: 1px solid var(--ag-color-brand-primary-border, rgba(46, 116, 184, 0.28));
  background: var(--ag-color-bg-surface, #fff);
  color: var(--ag-color-brand-primary, #2E74B8);
  font-family: inherit;
  font-weight: var(--ag-font-weight-medium, 500);
  cursor: pointer;
  transition: var(--ag-transition-colors, background-color 150ms ease, color 150ms ease);
}
.ag-stage-qchip:hover{ background: var(--ag-color-brand-primary-soft, #E3EDF9); }
/* Toggled-on state -- DOM contract for later JS (#ag-stage-tts's own
   aria-pressed, matching how a real toggle button communicates its state
   to assistive tech; the visual and the semantic state stay driven by the
   SAME attribute rather than a separate class a later task could forget to
   sync). */
.ag-stage-qchip[aria-pressed="true"]{
  background: var(--ag-gradient-button, linear-gradient(145deg, #2563eb, #4f46e5));
  color: var(--ag-color-text-on-primary, #fff);
  border-color: transparent;
}
.ag-stage-qchip:focus-visible{ outline: none; box-shadow: var(--ag-shadow-focus, 0 0 0 4px rgba(46, 116, 184, 0.16)); }

/* ---- voice HUD (.ag-vm-* -- design spec section 5) ---------------------- */

.ag-vm-bar{
  display: flex;
  align-items: center;
  gap: var(--ag-space-2, 8px);
  border: 1px solid var(--ag-color-border, #D9E1EE);
  border-radius: var(--ag-radius-full, 999px);
  background: var(--ag-color-bg-surface, #fff);
  padding: var(--ag-space-2, 8px) var(--ag-space-2, 8px) var(--ag-space-2, 8px) var(--ag-space-3, 12px);
  margin-block-end: var(--ag-space-2, 8px);
  box-shadow: var(--ag-shadow-xs, 0 1px 2px rgba(0, 0, 0, 0.04));
}
.ag-vm-bar[hidden]{ display: none; }
.ag-vm-lbl{ flex: 1; min-width: 0; }
#ag-vm-label{
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--ag-font-size-sm, 12px);
  font-weight: var(--ag-font-weight-bold, 600);
  color: var(--ag-color-text-heading, #1E284A);
}
#ag-vm-sub{
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--ag-font-size-xs, 10.5px);
  font-weight: var(--ag-font-weight-normal, 400);
  color: var(--ag-color-text-muted, #6B7491);
}

.ag-vm-eq{ display: flex; gap: 2.5px; align-items: center; height: 18px; flex-shrink: 0; }
.ag-vm-eq i{
  display: block;
  width: 3px;
  height: 5px;
  border-radius: var(--ag-radius-sm, 6px);
  background: var(--ag-color-brand-primary, #2E74B8);
  font-style: normal;
}
.ag-vm-eq i:nth-child(2){ animation-delay: .12s; }
.ag-vm-eq i:nth-child(3){ animation-delay: .24s; }
.ag-vm-eq i:nth-child(4){ animation-delay: .36s; }
.ag-vm-eq i:nth-child(5){ animation-delay: .48s; }

.ag-vm-exit{
  width: 26px;
  height: 26px;
  flex-shrink: 0;
  border: 1px solid var(--ag-color-border, #D9E1EE);
  border-radius: var(--ag-radius-full, 999px);
  background: var(--ag-color-bg-surface, #fff);
  color: var(--ag-color-text-body, #2A2A55);
  display: grid;
  place-items: center;
  cursor: pointer;
  transition: var(--ag-transition-colors, background-color 150ms ease);
}
.ag-vm-exit svg{ width: 12px; height: 12px; }
.ag-vm-exit:hover{ background: var(--ag-color-bg-surface-alt, #F9FAFD); }
.ag-vm-exit:focus-visible{ outline: none; box-shadow: var(--ag-shadow-focus, 0 0 0 4px rgba(46, 116, 184, 0.16)); }

/* State modifiers -- DOM contract for a later task's setV()-equivalent
   (mirrors the approved mockup's own `vbar.className = 'voicebar ' + state`
   pattern, prefixed to this codebase's own BEM-ish convention instead of
   the mockup's bare class names). Only "listening"/"speaking" animate the
   equalizer; "thinking" holds it static and muted; "paused" is a color-only
   state (booking-confirmation safety pause, design spec section 5) with no
   motion of its own. */
.ag-vm-bar--listening .ag-vm-eq i,
.ag-vm-bar--speaking .ag-vm-eq i{ animation: ag-vm-eq-bounce 1s ease-in-out infinite; }
.ag-vm-bar--speaking{ border-color: var(--ag-color-brand-primary-border, rgba(46, 116, 184, 0.28)); }
.ag-vm-bar--speaking .ag-vm-eq i{ background: var(--ag-color-brand-secondary, #1E284A); animation-duration: .7s; }
.ag-vm-bar--thinking .ag-vm-eq i{ background: var(--ag-color-text-muted, #6B7491); animation: none; height: 10px; }
.ag-vm-bar--paused{
  border-color: var(--ag-color-warning-border, rgba(251, 146, 60, 0.7));
  background: var(--ag-color-warning-softer, #fffbeb);
}

@keyframes ag-vm-eq-bounce{
  0%, 100%{ height: 5px; }
  50%{ height: 16px; }
}
@media (prefers-reduced-motion: reduce){
  .ag-vm-eq i{ animation: none !important; height: 10px; }
}

/* ---- history drawer (.ag-stage-drawer -- design spec section 4) -------- */

#ag-stage-drawer{
  position: absolute;
  inset-block: 0;
  inset-inline-start: -100%;
  width: min(264px, 84%);
  background: var(--ag-color-bg-surface, #fff);
  border-inline-end: 1px solid var(--ag-color-border, #D9E1EE);
  z-index: var(--ag-z-raised, 1);
  display: flex;
  flex-direction: column;
  /* inset-inline-start, not transform:translateX -- a logical PROPERTY
     animates correctly under RTL automatically; transform:translateX has no
     logical equivalent yet in any shipping browser (unlike translateY
     above, this axis genuinely needs to mirror). */
  transition: inset-inline-start 240ms ease;
}
#ag-stage-drawer[hidden]{ display: none; }
#ag-stage-drawer.ag-stage-drawer--open{ inset-inline-start: 0; }

@media (prefers-reduced-motion: reduce){
  #ag-stage-drawer{ transition: none; }
}

.ag-stage-drawer__head{
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--ag-space-2, 8px);
  padding: var(--ag-space-4, 16px) var(--ag-space-4, 16px) var(--ag-space-2, 8px);
}
.ag-stage-drawer__title{
  margin: 0;
  font-size: var(--ag-font-size-xs, 11px);
  text-transform: uppercase;
  letter-spacing: var(--ag-letter-spacing-wide, .07em);
  color: var(--ag-color-text-muted, #6B7491);
}
.ag-stage-drawer__list{ flex: 1; overflow-y: auto; padding: 0 var(--ag-space-2, 8px) var(--ag-space-2, 8px); }
.ag-stage-drawer__item{
  padding: var(--ag-space-2, 8px) var(--ag-space-3, 12px);
  border-radius: var(--ag-radius-xl, 12px);
  cursor: pointer;
}
.ag-stage-drawer__item:hover{ background: var(--ag-color-bg-surface-alt, #F9FAFD); }
.ag-stage-drawer__item--active{ background: var(--ag-color-brand-primary-soft, #E3EDF9); }
.ag-stage-drawer__item b{
  display: block;
  font-size: var(--ag-font-size-sm, 12.5px);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--ag-color-text-heading, #1E284A);
}
.ag-stage-drawer__item span{ font-size: var(--ag-font-size-xs, 11px); color: var(--ag-color-text-muted, #6B7491); }
.ag-stage-drawer__new{
  margin: var(--ag-space-2, 8px) var(--ag-space-3, 12px) var(--ag-space-3, 12px);
  border: 0;
  border-radius: var(--ag-radius-full, 999px);
  padding: var(--ag-space-2, 8px) var(--ag-space-3, 12px);
  background: var(--ag-gradient-button, linear-gradient(145deg, #2563eb, #4f46e5));
  color: var(--ag-color-text-on-primary, #fff);
  font: inherit;
  font-weight: var(--ag-font-weight-bold, 600);
  cursor: pointer;
}
.ag-stage-drawer__close:focus-visible,
.ag-stage-drawer__new:focus-visible{ outline: none; box-shadow: var(--ag-shadow-focus, 0 0 0 4px rgba(46, 116, 184, 0.16)); }

/* ---- message log: rows, bubbles, streaming cursor (Task 14) -------------
   The base layer every rendered turn sits on -- static/js/ranger/stage.js
   is the only thing that ever creates this markup (#ag-stage-body ships
   with only the hello state -- see that template's own header comment), so
   this class layer exists purely so the JS only needs to emit markup, no
   inline styles. The rich card types just below this block (.ag-stage-
   toolcard/.ag-stage-lcard/.ag-stage-confirm/.ag-stage-handoff) are a
   LATER task's own deliverable and nest INSIDE a .ag-stage__bubble the
   same way that block's own comment already documents. ---- */

.ag-stage__row{ display: flex; }
.ag-stage__row--user{ justify-content: flex-end; }
.ag-stage__row--bot{ justify-content: flex-start; }

.ag-stage__bubble{
  max-width: 86%;
  padding: var(--ag-space-2, 10px) var(--ag-space-3, 14px);
  border-radius: var(--ag-radius-2xl, 14px);
  font-size: var(--ag-font-size-md, 14px);
  line-height: var(--ag-line-height-normal, 1.5);
  overflow-wrap: anywhere;
}
.ag-stage__bubble--user{
  background: var(--ag-gradient-button, linear-gradient(145deg, #2563eb, #4f46e5));
  color: var(--ag-color-text-on-primary, #fff);
  border-end-end-radius: var(--ag-radius-sm, 6px);
}
.ag-stage__bubble--bot{
  background: var(--ag-color-bg-surface, #fff);
  color: var(--ag-color-text-body, #2A2A55);
  border: 1px solid var(--ag-color-border, #D9E1EE);
  border-end-start-radius: var(--ag-radius-sm, 6px);
}
.ag-stage__bubble--stopped{ opacity: .72; }
.ag-stage__stopped-tag{ color: var(--ag-color-text-muted, #6B7491); font-size: var(--ag-font-size-xs, 11px); }

/* mdLite()'s own tiny whitelist output -- <p>/<ul>/<li>/<b>/<i> -- gets its
   spacing reset here rather than inheriting the surface's global styles. */
.ag-stage__bubble p{ margin: 0 0 var(--ag-space-2, 8px); }
.ag-stage__bubble p:last-child{ margin-block-end: 0; }
.ag-stage__bubble ul{ margin: 0 0 var(--ag-space-2, 8px); padding-inline-start: var(--ag-space-4, 16px); }
.ag-stage__bubble ul:last-child{ margin-block-end: 0; }

.ag-stage__cursor{
  display: inline-block;
  width: 2px;
  height: 1em;
  margin-inline-start: 1px;
  vertical-align: text-bottom;
  background: currentColor;
  animation: ag-stage-caret-blink 1s step-end infinite;
}
@keyframes ag-stage-caret-blink{ 50%{ opacity: 0; } }
@media (prefers-reduced-motion: reduce){
  .ag-stage__cursor{ animation: none; opacity: .6; }
}

.ag-stage__bubble-acts{
  display: flex;
  align-items: center;
  gap: var(--ag-space-1, 4px);
  margin: var(--ag-space-1, 4px) 0 var(--ag-space-2, 8px);
}
.ag-stage__act{
  border: 0;
  background: none;
  cursor: pointer;
  color: var(--ag-color-text-muted, #6B7491);
  font-size: var(--ag-font-size-sm, 12px);
  padding: 3px var(--ag-space-1, 6px);
  border-radius: var(--ag-radius-full, 999px);
  transition: var(--ag-transition-colors, background-color 150ms ease, color 150ms ease);
}
.ag-stage__act:hover{ background: var(--ag-color-brand-primary-soft, #E3EDF9); color: var(--ag-color-brand-primary, #2E74B8); }
.ag-stage__act:focus-visible{ outline: none; box-shadow: var(--ag-shadow-focus, 0 0 0 4px rgba(46, 116, 184, 0.16)); }
.ag-stage__act--feedback[aria-pressed="true"]{ color: var(--ag-color-brand-primary, #2E74B8); }

@media (prefers-reduced-motion: reduce){
  .ag-stage__act{ transition: none; }
}

/* ---- message-log components ---------------------------------------------
   Rendered by a later task's JS, not this task's template (see that
   template's own header comment: #ag-stage-body holds only the hello state
   today). Classes declared now, prefixed ag-stage-*, so that task only
   needs to emit markup -- no new CSS -- matching the approved mockup's own
   .toolcard/.lcard/.confirmcard/.handoff structure and spacing. ---- */

.ag-stage-toolcard{
  border: 1px solid var(--ag-color-border, #D9E1EE);
  border-radius: var(--ag-radius-3xl, 16px);
  overflow: hidden;
  margin: var(--ag-space-2, 8px) 0;
  max-width: 92%;
  background: var(--ag-color-bg-surface, #fff);
  box-shadow: var(--ag-shadow-xs, 0 1px 2px rgba(0, 0, 0, 0.04));
}
.ag-stage-toolcard__head{
  display: flex;
  align-items: center;
  gap: var(--ag-space-2, 8px);
  padding: var(--ag-space-2, 8px) var(--ag-space-3, 12px);
  background: var(--ag-color-brand-primary-softer, rgba(46, 116, 184, 0.12));
  font-size: var(--ag-font-size-sm, 12.5px);
  font-weight: var(--ag-font-weight-bold, 600);
  color: var(--ag-color-text-heading, #1E284A);
}
.ag-stage-toolcard__head code{
  font-family: var(--ag-font-mono, "JetBrains Mono", "Fira Code", Consolas, monospace);
  font-size: var(--ag-font-size-xs, 11px);
  background: var(--ag-color-bg-surface-alt, #F9FAFD);
  border-radius: var(--ag-radius-sm, 6px);
  padding: 1px var(--ag-space-1, 7px);
  color: var(--ag-color-brand-secondary, #1E284A);
}
.ag-stage-toolcard__head .ag-stage-toolcard__ok{ color: var(--ag-color-success, #059669); }
.ag-stage-toolcard__body{ padding: var(--ag-space-1, 4px) var(--ag-space-3, 12px) var(--ag-space-3, 12px); }
.ag-stage-toolcard__spin{
  width: 15px;
  height: 15px;
  border-radius: var(--ag-radius-full, 999px);
  border: 2px solid var(--ag-color-brand-primary-soft, #E3EDF9);
  border-top-color: var(--ag-color-brand-primary, #2E74B8);
  /* static/css/animations.css's own @keyframes ag-spin, reused by name --
     same idiom section 1's .ag-orb already documents. */
  animation: ag-spin 0.8s linear infinite;
}
@media (prefers-reduced-motion: reduce){
  .ag-stage-toolcard__spin{ animation-duration: 1.6s; }
}

.ag-stage-lcard{
  min-width: 200px;
  max-width: 200px;
  flex-shrink: 0;
  border: 1px solid var(--ag-color-border, #D9E1EE);
  border-radius: var(--ag-radius-2xl, 14px);
  overflow: hidden;
  background: var(--ag-color-bg-surface, #fff);
  box-shadow: var(--ag-shadow-xs, 0 1px 2px rgba(0, 0, 0, 0.04));
  transition: var(--ag-transition-transform, transform 150ms ease), var(--ag-transition-shadow, box-shadow 150ms ease);
}
.ag-stage-lcard:hover{ box-shadow: var(--ag-shadow-md, 0 10px 22px rgba(24, 33, 51, 0.08)); transform: translateY(-2px); }
@media (prefers-reduced-motion: reduce){
  .ag-stage-lcard{ transition: box-shadow 150ms ease; }
  .ag-stage-lcard:hover{ transform: none; }
}
.ag-stage-lcard__th{ height: 92px; background-size: cover; background-position: center; position: relative; }
.ag-stage-lcard__price{
  position: absolute;
  inset-inline-end: var(--ag-space-2, 8px);
  inset-block-end: var(--ag-space-2, 8px);
  /* Existing overlay-scrim token, at its own alpha -- see this section's
     header note. */
  background: var(--ag-color-bg-overlay, rgba(15, 23, 42, 0.5));
  color: var(--ag-color-text-on-primary, #fff);
  font-size: var(--ag-font-size-xs, 11px);
  font-weight: var(--ag-font-weight-bold, 600);
  border-radius: var(--ag-radius-full, 999px);
  padding: 3px var(--ag-space-2, 9px);
  backdrop-filter: blur(4px);
}
.ag-stage-lcard__body{ padding: var(--ag-space-2, 10px) var(--ag-space-3, 12px); }
.ag-stage-lcard__body b{ font-size: var(--ag-font-size-sm, 13px); display: block; line-height: var(--ag-line-height-snug, 1.25); }
.ag-stage-lcard__sub{ font-size: var(--ag-font-size-xs, 11px); color: var(--ag-color-text-muted, #6B7491); margin-block-start: 2px; }
.ag-stage-lcard__stars{ color: var(--ag-color-rating-fill, #f4b45c); font-size: var(--ag-font-size-xs, 11px); margin-block-start: var(--ag-space-1, 4px); }
.ag-stage-lcard__go{ display: inline-block; margin-block-start: var(--ag-space-2, 7px); font-size: var(--ag-font-size-xs, 11.5px); font-weight: var(--ag-font-weight-bold, 600); color: var(--ag-color-brand-primary, #2E74B8); }

.ag-stage-confirm{
  border: 1.5px solid var(--ag-color-brand-primary-border, rgba(46, 116, 184, 0.28));
  border-radius: var(--ag-radius-3xl, 16px);
  background: var(--ag-gradient-brand-soft, linear-gradient(135deg, rgba(30,40,74,.18), rgba(46,116,184,.22), rgba(241,201,174,.22)));
  padding: var(--ag-space-3, 13px) var(--ag-space-4, 15px);
  margin: var(--ag-space-2, 8px) 0;
  max-width: 92%;
}
.ag-stage-confirm__title{
  display: flex;
  align-items: center;
  gap: var(--ag-space-2, 9px);
  font-size: var(--ag-font-size-sm, 13px);
  font-weight: var(--ag-font-weight-bold, 600);
  color: var(--ag-color-text-heading, #1E284A);
}
.ag-stage-confirm__sum{
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--ag-space-3, 14px);
  font-size: var(--ag-font-size-sm, 12.5px);
  color: var(--ag-color-text-body, #2A2A55);
  background: var(--ag-color-bg-surface, #fff);
  border: 1px solid var(--ag-color-border, #D9E1EE);
  border-radius: var(--ag-radius-xl, 12px);
  padding: var(--ag-space-2, 9px) var(--ag-space-3, 12px);
  margin: var(--ag-space-2, 10px) 0;
}
.ag-stage-confirm__amt{ white-space: nowrap; font-size: var(--ag-font-size-md, 16px); font-weight: var(--ag-font-weight-bold, 700); color: var(--ag-color-text-heading, #1E284A); }
.ag-stage-confirm__acts{ display: flex; gap: var(--ag-space-2, 8px); flex-wrap: wrap; }
.ag-stage-confirm__tip{ margin-block-start: var(--ag-space-2, 8px); font-size: var(--ag-font-size-xs, 10.5px); color: var(--ag-color-text-muted, #6B7491); }

.ag-stage-handoff{
  display: flex;
  gap: var(--ag-space-3, 11px);
  align-items: flex-start;
  border: 1px solid var(--ag-color-border, #D9E1EE);
  border-radius: var(--ag-radius-3xl, 16px);
  background: var(--ag-color-bg-surface, #fff);
  padding: var(--ag-space-3, 12px) var(--ag-space-4, 14px);
  margin: var(--ag-space-2, 8px) 0;
  max-width: 92%;
  box-shadow: var(--ag-shadow-xs, 0 1px 2px rgba(0, 0, 0, 0.04));
}
.ag-stage-handoff__ic{
  width: 38px;
  height: 38px;
  border-radius: var(--ag-radius-lg, 12px);
  background: var(--ag-color-success-softer, #f0fdf4);
  display: grid;
  place-items: center;
  font-size: var(--ag-font-size-xl, 17px);
  flex-shrink: 0;
}
.ag-stage-handoff b{ font-size: var(--ag-font-size-md, 13.5px); display: block; color: var(--ag-color-text-heading, #1E284A); }
.ag-stage-handoff p{ margin: 3px 0 0; font-size: var(--ag-font-size-sm, 12.5px); color: var(--ag-color-text-body, #2A2A55); }
.ag-stage-handoff__tk{
  font-family: var(--ag-font-mono, "JetBrains Mono", "Fira Code", Consolas, monospace);
  font-size: var(--ag-font-size-xs, 11px);
  color: var(--ag-color-brand-secondary, #1E284A);
  background: var(--ag-color-brand-primary-softer, rgba(46, 116, 184, 0.12));
  border-radius: var(--ag-radius-sm, 6px);
  padding: 1px var(--ag-space-1, 7px);
  display: inline-block;
  margin-block-end: var(--ag-space-1, 6px);
}

/* ---- Task 16 additions: the handoff card's "continues in Messages" link,
   and the message-log's per-bubble sender label (roleLabel(), future-
   proofing for a human reply landing in this same log later -- see that
   function's own comment in stage.js). Additive only -- no existing rule
   above is changed. ---- */
.ag-stage-handoff__link{
  display: inline-block;
  margin-block-start: 2px;
  font-size: var(--ag-font-size-xs, 11.5px);
  font-weight: var(--ag-font-weight-bold, 600);
  color: var(--ag-color-brand-primary, #2E74B8);
  text-decoration: none;
}
.ag-stage-handoff__link:hover{ text-decoration: underline; }
.ag-stage-handoff__link:focus-visible{
  outline: none;
  border-radius: var(--ag-radius-sm, 4px);
  box-shadow: var(--ag-shadow-focus, 0 0 0 4px rgba(46, 116, 184, 0.16));
}
.ag-stage__bubble-role{
  display: block;
  font-size: var(--ag-font-size-xs, 11px);
  font-weight: var(--ag-font-weight-bold, 600);
  color: var(--ag-color-text-muted, #6B7491);
  margin-block-end: 2px;
}

/* ---- Task 15 additions: listing-cards row, confirm-gate buttons, drawer
   loading/empty/error/load-more. Extends this section's own established
   component classes above (.ag-stage-lcard/.ag-stage-confirm/
   .ag-stage-drawer*) with the pieces static/js/ranger/stage.js's new
   renderCards()/renderConfirmGate()/fetchSessionsPage() need -- no existing
   rule above is changed. ---- */

/* .ag-stage-lcard itself carries min/max-width but no explicit display
   (T13's own rule, unchanged) -- this row wraps a set of them in
   `display:flex`, which blockifies each card (a flex item's outer display
   is blockified per spec) so those widths take effect whether stage.js
   rendered a given card as an `<a>` (safe, in-platform url) or a `<span>`
   (unsafe/absent url -- see buildListingCard()'s own comment) -- both tags
   are inline by default otherwise, which would ignore width entirely. */
.ag-stage-cards{
  display: flex;
  gap: var(--ag-space-2, 8px);
  overflow-x: auto;
  margin: var(--ag-space-2, 8px) 0;
  padding-block-end: var(--ag-space-1, 4px);
}
/* Neutralizes the UA default blue/underline `<a>` styling on a safe card --
   a no-op on the `<span>` variant (span has no default link styling to
   begin with), so one rule covers both tag choices. */
.ag-stage-lcard{ text-decoration: none; color: inherit; }

/* Confirm / Not-now -- a filled primary and an outlined secondary, matching
   .ag-stage-drawer__new's gradient and .ag-iconbtn's outline pairing
   elsewhere in this file rather than inventing a third button language. */
.ag-stage-confirm__btn{
  border: 1px solid var(--ag-color-border, #D9E1EE);
  border-radius: var(--ag-radius-full, 999px);
  padding: var(--ag-space-2, 8px) var(--ag-space-4, 16px);
  background: var(--ag-color-bg-surface, #fff);
  color: var(--ag-color-text-body, #2A2A55);
  font: inherit;
  font-weight: var(--ag-font-weight-bold, 600);
  cursor: pointer;
  transition: var(--ag-transition-colors, background-color 150ms ease, color 150ms ease);
}
.ag-stage-confirm__btn:hover{ background: var(--ag-color-brand-primary-soft, #E3EDF9); }
.ag-stage-confirm__btn:focus-visible{ outline: none; box-shadow: var(--ag-shadow-focus, 0 0 0 4px rgba(46, 116, 184, 0.16)); }
.ag-stage-confirm__btn--primary{
  border-color: transparent;
  background: var(--ag-gradient-button, linear-gradient(145deg, #2563eb, #4f46e5));
  color: var(--ag-color-text-on-primary, #fff);
}
.ag-stage-confirm__btn--primary:hover{ filter: brightness(1.06); }
/* The confirm gate disables both buttons the instant either is tapped
   (stage.js's own resolve() -- the money boundary's "the user's tap is the
   only thing that may advance it" requirement, belt-and-braces against a
   double-tap double-firing the send() it triggers). */
.ag-stage-confirm__btn:disabled{ opacity: .55; cursor: not-allowed; }

/* History drawer: loading / empty / error states share one look (centered,
   muted, roomy) -- distinguished by their message text, not their style. */
.ag-stage-drawer__loading,
.ag-stage-drawer__empty,
.ag-stage-drawer__error{
  margin: var(--ag-space-4, 16px) var(--ag-space-3, 12px);
  font-size: var(--ag-font-size-sm, 12.5px);
  color: var(--ag-color-text-muted, #6B7491);
  text-align: center;
}
.ag-stage-drawer__more{
  display: block;
  margin: var(--ag-space-2, 8px) var(--ag-space-3, 12px);
  border: 1px solid var(--ag-color-border, #D9E1EE);
  border-radius: var(--ag-radius-full, 999px);
  padding: var(--ag-space-1, 6px) var(--ag-space-3, 12px);
  background: var(--ag-color-bg-surface, #fff);
  color: var(--ag-color-brand-primary, #2E74B8);
  font: inherit;
  font-weight: var(--ag-font-weight-medium, 500);
  cursor: pointer;
}
.ag-stage-drawer__more:hover{ background: var(--ag-color-brand-primary-soft, #E3EDF9); }
.ag-stage-drawer__more:focus-visible{ outline: none; box-shadow: var(--ag-shadow-focus, 0 0 0 4px rgba(46, 116, 184, 0.16)); }

/* ---- responsive: composer/footer padding tightens under the same
   breakpoints section 1's dock already uses, so the whole Ranger surface
   shrinks in step -- not just the launcher that opens it. ---- */
@media (max-width: 767.98px){
  #ag-stage-veil{ padding: var(--ag-space-3, 12px); }
  .ag-stage__head{ padding: var(--ag-space-3, 12px) var(--ag-space-4, 16px); }
  #ag-stage-body{ padding: var(--ag-space-4, 16px) var(--ag-space-4, 16px) var(--ag-space-2, 8px); }
  .ag-stage__foot{ padding: var(--ag-space-1, 4px) var(--ag-space-4, 16px) var(--ag-space-3, 12px); }
}
