/**
 * FTA Agent Hub - Global Design System
 *
 * Single source of truth for design tokens, typography, and base styles.
 * All pages inherit these variables via the _head.html partial.
 *
 * Brand colours: Navy #0a192f, Pink #e6007e
 * Font pairing: DM Serif Display (headings) + Inter (body/UI)
 * Colour philosophy: NO neutral grey -- blue-tinted whites on sidebar, dark slates on body
 */

/* ==========================================================================
   Design Tokens
   ========================================================================== */

:root {
  /* ── Brand ──────────────────────────────────────────────────────── */
  /* Aligned to marketing site (https://fta-website.azurewebsites.net) per
   * design-implementation-reviewer audit 2026-05-26 (PR #1912). Superseded the
   * original pre-marketing navy/pink introduced in PR #144. These three tokens
   * are the single source of truth for brand colour across the whole app. */
  --fta-navy: #0a192f;
  --fta-pink: #e6007e;
  --fta-pink-hover: #c40069;

  /* ── AI provenance marker (Stream B / mig 294) ──────────────────── */
  --ai-fill-marker: #c98a04;     /* amber — distinct from brand-pink + red validation */
  --ai-fill-marker-soft: rgba(201, 138, 4, 0.06);
  --prior-year-accent: #6366f1;  /* indigo — "changed from last year" (renewal adopt) */
  --prior-year-accent-soft: rgba(99, 102, 241, 0.06);
  --broker-change-marker: #0d9488; /* teal — "changed by broker" (mig 524) — distinct from AI amber/pink + indigo */
  --broker-change-marker-soft: rgba(13, 148, 136, 0.07);

  /* ── Sidebar palette ────────────────────────────────────────────── */
  --sidebar-bg: var(--fta-navy);
  --sidebar-width-expanded: 224px;
  --sidebar-width-collapsed: 52px;
  --sidebar-border: rgba(226, 232, 240, 0.08);

  /* ── Agent UI (bottom floating pill) ─────────────────────────── */
  --agent-ui-focus: var(--fta-pink); /* Focus ring uses FTA brand pink */
  --agent-ui-z: var(--z-agent-ui); /* alias into the canonical z-scale */
  --agent-ui-shadow: 0 10px 40px -10px rgba(0, 0, 0, 0.1);

  --text-primary: #e2e8f0;              /* near-white with cool tint */
  --text-active: #ffffff;
  --text-section: #94a8d0;              /* blue-tinted label */
  --text-dim: #a4b4d4;                  /* settings/footer - soft blue */

  --accent: var(--fta-pink);
  --accent-bg: rgba(230, 0, 126, 0.14);
  --accent-badge-bg: rgba(230, 0, 126, 0.18);

  --card-border: rgba(226, 232, 240, 0.1);
  --hover-bg: rgba(226, 232, 240, 0.08);

  /* ── Body/content palette ───────────────────────────────────────── */
  --body-bg: #f1f5f9;
  --body-surface: #ffffff;
  --body-surface-alt: #f8fafc;
  --body-border: #e2e8f0;
  /* Slate steps below the hairline — the only neutrals dark enough to draw a
     scrollbar thumb or a navy-tinted chip against. Blue-tinted, per the
     No-Grey Rule; added with the notifications panel. */
  --slate-300: #cbd5e1;
  --slate-400: #94a3b8;
  --navy-tint: #e7eaf0;          /* soft navy chip fill (icon tiles) */
  --pink-wash: #fdf7fa;          /* faintest pink — unread row hover only */
  /* Hairline divider alias. Was referenced ~40× as var(--line, #e6e8ef) but
   * never defined — every call fell back to the literal. Aliased to the border
   * token so dividers track the one border colour. */
  --line: var(--body-border);
  --body-heading: #0f172a;
  --body-text: #1e293b;
  --body-text-label: #334155;

  /* ── Typography ─────────────────────────────────────────────────── */
  --font-heading: 'DM Serif Display', Georgia, serif;
  --font-body: 'Inter', system-ui, -apple-system, sans-serif;
  /* Display face for primary headings on entry surfaces (broker dashboard
   * welcome, quote presentation). Points at Manrope first to match the
   * marketing site brand; falls back to the self-hosted Inter that's
   * already loaded. When the Manrope woff2 asset is self-hosted in a
   * future PR (fonts.css addition), the marketing-parity heading style
   * activates without a code change here. */
  --font-display: 'Manrope', var(--font-body);

  /* ── Spacing ────────────────────────────────────────────────────── */
  --space-xs: 4px;
  --space-sm: 8px;
  --space-md: 16px;
  --space-lg: 24px;
  --space-xl: 32px;

  /* ── Radii ──────────────────────────────────────────────────────── */
  --radius-sm: 6px;
  --radius-md: 10px;
  --radius-lg: 16px;
  /* Pill / circle. Referenced by notifications.css (bell badge, avatars, dots)
     and the CRM chips — it was NEVER defined, so `border-radius: var(--radius-full)`
     computed to the initial 0 and every one of those rendered SQUARE. */
  --radius-full: 9999px;

  /* ── Broker tier badges ───────────────────────────────────────────
     Gold / Silver / Bronze / Inactive from broker_scores.tier. Metal names, so
     no brand or status token fits — these ARE the palette. Kept here rather than
     in crm-directory.css because portfolio.html carries the same three pairs
     inline (orphaned since the tiles that used them were removed); a second
     surface should adopt these rather than re-typing the hex. */
  --tier-gold-bg: #fef3c7;
  --tier-gold-fg: #b45309;
  --tier-silver-bg: #f1f5f9;
  --tier-silver-fg: #475569;
  --tier-bronze-bg: #ffedd5;
  --tier-bronze-fg: #c2410c;

  /* ── AI / Weaver ──────────────────────────────────────────────── */
  --ai-blue: #2563eb;
  --ai-blue-light: #eff6ff;
  --ai-border: rgba(37, 99, 235, 0.2);
  --ai-emerald: #34d399;
  --ai-amber: #f59e0b;
  --ai-gradient: linear-gradient(135deg, #2563eb, #7c3aed);

  /* Action blue — Tailwind blue-800. Established across quoteapp.css for
     secondary-action surfaces (status badges, active tabs, the Email Broker
     button). Distinct from `--ai-blue` (#2563eb) which is reserved for
     AI/Weaver chrome. ~10:1 contrast on white — WCAG AAA. */
  --fta-action-blue: #1e40af;
  --fta-action-blue-focus: #3b82f6;

  /* ── Status ───────────────────────────────────────────────────── */
  --status-success: #16a34a;
  --status-error: #dc2626;
  --status-warning: #f59e0b;
  --status-info: #3b82f6;
  /* Soft status backgrounds (50-level tints). These were referenced by the
     broker-portal status pills + calm cards but never defined — leaving those
     surfaces transparent. Defining them here (WP-4) fixes that and gives the
     portal a semantic-bg token set distinct from brand pink. */
  --status-success-bg: #f0fdf4;
  --status-error-bg: #fef2f2;
  --status-warning-bg: #fffbeb;
  --status-info-bg: #eff6ff;

  /* ── Version-chain status vocabulary ─────────────────────────────
     The quote version chain (v1 / E1 / …) renders one pill per state.
     Every pill is the same shape — soft fill, 1px border in its own
     hue, dark hue text — so state reads by COLOUR, never by whether
     the chip happens to look filled. Held separately from --status-*
     because the chain's states have no --status- equivalent:
     Superseded (bound but replaced) and Closed (a manually closed
     duplicate) are different facts and must never collapse into one
     grey, which is exactly how they used to render. Every fg/bg pair
     clears 4.5:1. */
  --vchain-active-bg: #dcfce7;
  --vchain-active-fg: #166534;
  --vchain-active-line: #86efac;
  --vchain-draft-bg: #dbeafe;        /* matches .qa-status-quoted — the */
  --vchain-draft-fg: #1e40af;        /* documented informational badge */
  --vchain-draft-line: #93c5fd;
  --vchain-inert-bg: #e2e8f0;        /* superseded / cancelled / NTU */
  --vchain-inert-fg: #475569;
  --vchain-inert-line: #cbd5e1;
  --vchain-closed-bg: #ffffff;       /* outlined, not filled — the one */
  --vchain-closed-fg: #64748b;       /* state that reads as "set aside" */
  --vchain-closed-line: #94a3b8;
  --vchain-declined-bg: #fee2e2;
  --vchain-declined-fg: #b91c1c;
  --vchain-declined-line: #fca5a5;
  /* Amber hairline + readable amber-brown text on --status-warning-bg.
     --status-warning is a fill, not a text colour: on that background it
     clears only 2.2:1, so body copy on an amber surface uses this instead. */
  --status-warning-line: #fcd34d;
  --status-warning-text: #92400e;
  /* Same reason for success: --status-success is 3.3:1 on white, so a
     green figure or label on a white surface uses this (4.9:1). */
  --status-success-text: #15803d;
  /* And error: --status-error clears 4.8:1 on white but only 4.4:1 on its
     own --status-error-bg, so red text on either surface uses this (5.9:1+). */
  --status-error-text: #b91c1c;

  /* ── Business type ────────────────────────────────────────────────
     A quote's category, not its state: sky = new business, violet =
     renewal (the hues of My Work's type chips). Chart fills and swatches,
     not text: sky is 4.1:1 on white. The two sit a lightness step apart
     so a stacked bar still splits for colour-blind readers. */
  --biz-new-business: #0284c7;
  --biz-renewal: #6d28d9;

  /* ── Semantic colour aliases (used in inline JS styles) ───────── */
  --color-success: #16a34a;
  --color-danger: #dc2626;
  --color-warning: #d97706;
  --color-muted: #64748b;
  --body-text-muted: #64748b;

  /* ── Font: Mono ───────────────────────────────────────────────── */
  --font-mono: 'SF Mono', 'Fira Code', 'JetBrains Mono', monospace;

  /* ── Responsive tokens (iPad / iPhone overhaul, 2026-05) ────────
     Breakpoints are documentation: CSS @media rules must hardcode the
     pixel value (custom properties are not allowed inside @media). The
     tokens here are the canonical reference — when authoring a new
     @media block, copy the pixel value from this table.

       mobile    < 640px   iPhone SE → iPhone 16 Pro Max portrait
       tablet    640–1023  iPad Mini portrait, iPad Pro 11 portrait
       desktop   ≥ 1024px  iPad Pro landscape, all desktops

     Tap target minimum is Apple HIG 44pt = 44px CSS. WCAG 2.5.8 (AA)
     accepts 24px; we aim for the stricter Apple bar on all touch-eligible
     viewports.

     Safe-area insets are populated by Safari only when the viewport meta
     includes `viewport-fit=cover`. On non-iOS browsers env() returns 0,
     so this is safe to reference everywhere. */
  --bp-mobile: 640px;            /* doc-only — see comment above */
  --bp-tablet: 1024px;           /* doc-only — see comment above */

  --tap-min: 44px;               /* Apple HIG minimum tap target */

  --sidebar-width-drawer: 280px; /* off-canvas drawer width on touch viewports */

  --safe-top: env(safe-area-inset-top, 0px);
  --safe-right: env(safe-area-inset-right, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --safe-left: env(safe-area-inset-left, 0px);

  /* ── Type scale ─────────────────────────────────────────────────
     Sizes/weights/line-heights were hardcoded per component (h1/h2/h3
     below, plus raw px everywhere else). These are the canonical scale;
     the base heading rules point at them. In rem so text follows the
     reader's browser font size; at the default 16px root they are the
     px values noted. */
  --font-size-xs: 0.6875rem;  /* 11px — badges, pills, dense metadata */
  --font-size-sm: 0.75rem;    /* 12px */
  --font-size-body-sm: 0.8125rem; /* 13px — buttons, dense tables and fields (DESIGN.md bodySm) */
  --font-size-base: 0.875rem; /* 14px — default body/UI text */
  --font-size-md: 1rem;       /* 16px — form controls (also the iOS no-zoom floor) */
  --font-size-lg: 1.125rem;   /* 18px */
  --font-size-xl: 1.25rem;    /* 20px — h2 */
  --font-size-2xl: 1.5rem;    /* 24px — h1 */
  --font-weight-normal: 400;
  --font-weight-medium: 500;
  --font-weight-semibold: 600;
  --font-weight-bold: 700;
  --line-height-tight: 1.2;
  --line-height-normal: 1.5;
  --line-height-relaxed: 1.7;

  /* ── Elevation ──────────────────────────────────────────────────
     Was the only shadow scale in the codebase, previously living as the
     broker-portal-only --bp-shadow-* set. Promoted here as canonical; the
     --bp-shadow-* aliases now point back to these (single definition). */
  --shadow-ring: 0 0 0 1px rgba(0, 0, 0, 0.03);
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.04);
  --shadow: var(--shadow-ring), 0 2px 4px rgba(0, 0, 0, 0.02), 0 4px 8px rgba(0, 0, 0, 0.03);
  --shadow-md: var(--shadow-ring), 0 4px 8px rgba(0, 0, 0, 0.04), 0 8px 16px rgba(0, 0, 0, 0.06);
  --shadow-lg: var(--shadow-ring), 0 8px 16px rgba(0, 0, 0, 0.06), 0 16px 32px rgba(0, 0, 0, 0.08);
  --shadow-xl: 0 16px 48px rgba(0, 0, 0, 0.12);

  /* ── Motion ─────────────────────────────────────────────────────
     Promoted from the broker-portal --bp-ease/--bp-transition* set. */
  --ease-standard: cubic-bezier(0.16, 1, 0.3, 1);
  --transition-fast: 120ms var(--ease-standard);
  --transition-base: 160ms var(--ease-standard);
  --transition-slow: 200ms var(--ease-standard);

  /* ── Z-index scale ──────────────────────────────────────────────
     Canonical stacking order. Previously only --agent-ui-z existed and
     everything else used scattered raw z-index values (mapping those onto
     this scale is a tracked follow-up). */
  --z-base: 1;
  --z-dropdown: 100;
  --z-sticky: 200;
  --z-sidebar: 300;
  --z-overlay: 800;
  --z-agent-ui: 900;
  --z-modal: 1000;
  --z-toast: 1100;
  /* Slide-in record drawers (broker map / broker house scores). ABOVE Leaflet,
     whose panes start at 400 and whose controls sit at 1000, so a map cannot
     draw over an open drawer. */
  --z-drawer: 1200;
  /* A modal opened FROM a drawer has to clear it: #btn-log-visit lives inside
     the drawer, so at the drawer's old z-index the Log Visit dialog opened
     underneath the thing that opened it. */
  --z-drawer-modal: 1300;
}

/* ==========================================================================
   Low-confidence (autoquotes) field marker
   --------------------------------------------------------------------------
   An auto-created quote ships its AI-disputed / inferred fields flagged so the
   forwarding UW verifies them. Amber border + soft fill via the shared warning
   tokens (never hardcode a colour). Added/cleared by quote-editor-provenance.js.
   Lives in global.css (loaded by BOTH the classic and V2 editor pages) so the
   marker renders on both — the V2-only stylesheet would skip the classic editor.
   ========================================================================== */
.split-input.field--low-confidence,
select.field--low-confidence,
input.field--low-confidence {
  border-color: var(--status-warning, #f59e0b);
  border-width: 2px;
  background-color: var(--status-warning-bg, #fffbeb);
}
.split-input.field--low-confidence:focus,
select.field--low-confidence:focus,
input.field--low-confidence:focus {
  border-color: var(--status-warning, #f59e0b);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--status-warning, #f59e0b) 25%, transparent);
}

/* ==========================================================================
   Base Styles
   ========================================================================== */

body {
  font-family: var(--font-body);
  background: var(--body-bg);
  color: var(--body-text);
  margin: 0;
  padding: 0;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* ==========================================================================
   Typography
   ========================================================================== */

h1, h2, h3 {
  font-family: var(--font-heading);
  font-weight: var(--font-weight-normal);
  color: var(--body-heading);
}

h1 { font-size: var(--font-size-2xl); }
h2 { font-size: var(--font-size-xl); }
h3 { font-size: var(--font-size-md); }

/* Serif headings render at ONE weight, everywhere.
   DM Serif Display ships a single 400 face (see fonts.css), and DESIGN.md
   sets every serif tier at weight 400. But page headers get pushed to 600/
   700/800 in three different ways — a Tailwind `font-semibold` utility, a
   component-CSS rule (e.g. iris-report.css h1 at 700), or an inline style —
   and on a single-weight font the browser then synthesises FAUX-bold. That
   is the only reason some page headers looked heavier than others.
   Forbidding weight synthesis pins every serif heading to its true 400 glyph
   regardless of which mechanism set the weight, so all pages read alike.
   Inter (variable 300–700) and the mono stack carry real weights, so this is
   a no-op for them. The `.font-serif` line additionally makes the common
   Tailwind heading's *computed* weight honest and covers the rare browser
   without font-synthesis support. */
html { font-synthesis-weight: none; }
.font-serif { font-weight: var(--font-weight-normal, 400); }

/* ==========================================================================
   Touch viewport base rules (iPad / iPhone overhaul, 2026-05)
   ========================================================================== */

/* iOS Safari zooms the viewport when a focused input has font-size < 16px.
   Prevent the zoom on all touch viewports by promoting form-control text
   to 16px. Below 640px the design is touch-first regardless. Component
   CSS can opt out per element if a denser desktop look is needed inside
   a desktop-only modal. */
@media (max-width: 1023px) {
  input,
  select,
  textarea {
    font-size: 16px;
  }
}

/* Safe-area padding for notched iPhones / iPad Pro USB-C side.
   env() resolves to 0 on non-iOS browsers, so this is a no-op there.
   Applied to body so fixed-position children (sidebar, agent pill)
   can read --safe-* tokens directly. */
@supports (padding: env(safe-area-inset-top)) {
  body {
    padding-left: var(--safe-left);
    padding-right: var(--safe-right);
  }
}

/* Body scroll lock — applied while a drawer or full-screen modal is open.
   Reused across the sidebar drawer (sidebar.js) and future modal patterns.
   `overflow: hidden` alone leaks scroll on iOS Safari; the position:fixed
   trick is the canonical fix but loses scroll position, so callers that
   need to restore it should save window.scrollY before applying and restore
   after removing. */
body.body-no-scroll {
  overflow: hidden;
}
@supports (-webkit-touch-callout: none) {
  /* iOS Safari only — overflow:hidden isn't enough; lock with position:fixed */
  body.body-no-scroll {
    position: fixed;
    width: 100%;
  }
}

/* ==========================================================================
   Test Mode (PVT)
   Activated by ?test=true. The inline script in _head.html sets .test-mode on
   <html> synchronously, so the banner is in the first paint (and on <body>
   once it exists, for descendant selectors that need it).

   The banner is the first row of the content column, in normal flow. As a
   fixed strip over the viewport it lay on top of the sidebar's logo row, and
   making room under it took padding on <html> and <body> — both carry
   .test-mode, so the room was doubled: a 28px gap under the banner and a page
   56px taller than the viewport. In flow it needs no padding: the sidebar is
   untouched, the column follows the sidebar's collapsed and drawer states as
   the page always does, and the quote editor (a flex column of fixed height)
   gives its panels whatever height the banner leaves.
   ========================================================================== */

html.test-mode .main-content::before {
  content: "TEST MODE — quotes built here are flagged as test and won't appear in reports or sync to Salesforce.";
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
  box-sizing: border-box;
  min-height: 1.75rem;
  padding: var(--space-xs) var(--space-md);
  background: var(--status-warning);
  color: var(--body-heading);
  font-family: var(--font-body);
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-semibold);
  letter-spacing: 0.02em;
  text-align: center;
  text-wrap: balance;
}

html.test-mode .sidebar {
  border-left: 3px solid var(--status-warning);
}

/* ==========================================================================
   Modal pattern — the reusable .qa-modal system
   --------------------------------------------------------------------------
   Promoted here from quoteapp.css (2026-08-12). Its JS half, /js/modal.js,
   has always been global — bundled into head-bundle.min.js and loaded by
   _head.html on EVERY page — while the CSS sat in quoteapp.css, which only
   QuoteApp pages load. So `window.FTAModal` worked everywhere and the modal
   rendered nowhere else, and the first non-QuoteApp adopter (the Claims
   export modal) would have had to copy the block. One definition instead,
   same pattern as the --shadow-* / --bp-shadow-* promotion above.

   Behaviour:
     ≥1024px       → centered modal (max-width 560, max-height 80vh)
     640–1023px    → bottom-sheet (slides up from bottom, max-height 88vh)
     <640px        → full-screen (100vw × 100vh − safe-area)
   Scroll lock, Escape, overlay-click, focus trap and focus restore are all
   handled by modal.js. Close button is 44pt minimum, top-right of header.
   ========================================================================== */

.qa-modal {
  position: fixed;
  inset: 0;
  z-index: 1100; /* above sidebar drawer (1000) and agent pill (900) */
  display: none;
  align-items: center;
  justify-content: center;
  padding: var(--space-lg);
}
.qa-modal[data-open="true"] {
  display: flex;
}
.qa-modal-overlay {
  position: absolute;
  inset: 0;
  background: rgba(11, 22, 54, 0.5);
  cursor: pointer;
}
.qa-modal-content {
  position: relative;
  background: var(--body-surface, #ffffff);
  border-radius: var(--radius-lg, 16px);
  box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
  width: 100%;
  max-width: 560px;
  max-height: 80vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.qa-modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-lg);
  border-bottom: 1px solid var(--body-border, #e2e8f0);
}
.qa-modal-title {
  font-family: var(--font-heading);
  font-size: 1.125rem;
  color: var(--body-heading, #0f172a);
  margin: 0;
}
.qa-modal-close {
  width: var(--tap-min);
  height: var(--tap-min);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: none;
  border-radius: var(--radius-sm);
  color: var(--body-text-muted, #64748b);
  cursor: pointer;
}
.qa-modal-close:hover,
.qa-modal-close:focus-visible {
  background: var(--body-surface-alt, #f8fafc);
  color: var(--body-text, #1e293b);
}
.qa-modal-body {
  padding: var(--space-lg);
  overflow-y: auto;
  flex: 1;
  -webkit-overflow-scrolling: touch;
}
.qa-modal-footer {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-sm);
  padding: var(--space-md) var(--space-lg);
  border-top: 1px solid var(--body-border, #e2e8f0);
}

@media (max-width: 1023px) {
  /* Bottom-sheet on tablet — content slides up from the bottom edge with
     rounded top corners only. Padding around the modal collapses so the
     sheet hugs the viewport sides. */
  .qa-modal {
    padding: 0;
    align-items: flex-end;
  }
  .qa-modal-content {
    max-width: none;
    width: 100%;
    max-height: calc(88vh - var(--safe-bottom));
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
    padding-bottom: var(--safe-bottom);
  }
}

@media (max-width: 640px) {
  /* Full-screen on phone — covers the entire viewport including safe-area
     padding. Drops border-radius for an immersive feel. */
  .qa-modal-content {
    max-height: 100vh;
    height: 100vh;
    border-radius: 0;
    padding-top: var(--safe-top);
    padding-bottom: var(--safe-bottom);
  }
}

/* ==========================================================================
   Release Notes (modal)
   Auto-opens on first login when currentVersion changes; re-openable via
   sidebar footer link → window.FTAReleaseNotes.show().
   ========================================================================== */

.fta-rn-overlay {
  position: fixed; inset: 0; z-index: 10000;
  background: rgba(11, 22, 54, 0.55);
  backdrop-filter: blur(4px);
  display: flex; align-items: center; justify-content: center;
  padding: 24px;
  font-family: var(--font-body);
}
.fta-rn-dialog {
  background: #fff;
  border-radius: 8px;
  width: 100%;
  max-width: 720px;
  max-height: 90vh;
  display: flex; flex-direction: column;
  box-shadow: 0 24px 60px rgba(0,0,0,0.35);
  position: relative;
}
.fta-rn-close {
  position: absolute; top: 8px; right: 12px;
  background: none; border: none;
  font-size: 28px; line-height: 1;
  color: #94a3b8; cursor: pointer;
  padding: 4px 10px;
}
.fta-rn-close:hover { color: var(--fta-navy); }
.fta-rn-body {
  overflow-y: auto;
  padding: 14px 48px 8px 32px;
  flex: 1;
}
/* History grouped year > month > release. Months and releases are <details>;
   only the newest month and the newest release start open. */
.fta-rn-year {
  font-family: var(--font-heading);
  font-weight: 400;
  font-size: 28px;
  color: var(--fta-navy);
  margin: 12px 0 4px;
}
.fta-rn-month { border-bottom: 1px solid #e2e8f0; }
.fta-rn-month-head {
  list-style: none;
  cursor: pointer;
  position: relative;
  display: flex; align-items: baseline; gap: 10px;
  padding: 10px 0 10px 22px;
}
.fta-rn-month-head::-webkit-details-marker { display: none; }
.fta-rn-month-name {
  font-size: 15px;
  font-weight: 700;
  color: var(--fta-navy);
}
.fta-rn-month-count { font-size: 12.5px; color: var(--color-muted); }
.fta-rn-month-head:hover .fta-rn-month-name { color: var(--fta-pink); }
.fta-rn-month-head:focus-visible { outline: 2px solid var(--fta-pink); outline-offset: 2px; border-radius: 4px; }
.fta-rn-month > .fta-rn-release { margin-left: 22px; }
.fta-rn-release { border-top: 1px dashed #e2e8f0; }
.fta-rn-head {
  list-style: none;
  cursor: pointer;
  position: relative;
  padding: 10px 0 10px 22px;
}
.fta-rn-head::-webkit-details-marker { display: none; }
/* Chevron on the left, clear of the dialog's close button. */
.fta-rn-month-head::before,
.fta-rn-head::before {
  content: '';
  position: absolute; left: 2px; top: 50%;
  width: 7px; height: 7px;
  border-right: 2px solid #94a3b8;
  border-bottom: 2px solid #94a3b8;
  transform: translateY(-50%) rotate(-45deg);
  transition: transform 0.15s ease;
}
.fta-rn-month[open] > .fta-rn-month-head::before,
.fta-rn-release[open] > .fta-rn-head::before { transform: translateY(-75%) rotate(45deg); }
.fta-rn-head:hover .fta-rn-title { color: var(--fta-pink); }
.fta-rn-head:focus-visible { outline: 2px solid var(--fta-pink); outline-offset: 2px; border-radius: 4px; }
.fta-rn-title {
  font-family: var(--font-heading);
  font-weight: 400;
  font-size: 16px;
  color: var(--fta-navy);
  margin: 0;
}
.fta-rn-release[open] > .fta-rn-head .fta-rn-title { font-size: 24px; }
.fta-rn-date {
  color: var(--fta-pink);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  margin-bottom: 2px;
}
.fta-rn-content { padding: 4px 0 20px 22px; }
.fta-rn-intro {
  color: #475569;
  font-size: 14px;
  line-height: 1.55;
  margin: 0 0 20px;
}
.fta-rn-section { margin-bottom: 20px; }
.fta-rn-section-heading {
  font-family: var(--font-body);
  font-size: 15px;
  font-weight: 700;
  color: var(--fta-navy);
  margin: 0 0 10px;
  display: flex; align-items: center; gap: 8px;
}
.fta-rn-section-icon {
  font-size: 18px;
  line-height: 1;
}
.fta-rn-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex; flex-direction: column; gap: 10px;
}
.fta-rn-item {
  background: #f8fafc;
  border: 1px solid #e2e8f0;
  border-radius: 6px;
  padding: 10px 12px;
  font-size: 13.5px;
  line-height: 1.5;
  color: #1f2937;
}
.fta-rn-item-text strong { color: var(--fta-navy); font-weight: 600; }
.fta-rn-item-text code {
  background: #e2e8f0;
  padding: 1px 5px;
  border-radius: 3px;
  font-size: 12px;
  font-family: var(--font-mono);
}
.fta-rn-item-text a { color: var(--fta-pink); text-decoration: underline; }
.fta-rn-img {
  display: block;
  max-width: 100%;
  margin: 8px 0 0;
  border: 1px solid #cbd5e1;
  border-radius: 4px;
  /* Reserve aspect so release-notes images don't push text down on load */
  aspect-ratio: 16 / 9;
  object-fit: cover;
}
.fta-rn-foot {
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px solid #e2e8f0;
  font-size: 12.5px;
  color: #475569;
}
.fta-rn-foot p { margin: 0; }
.fta-rn-actions {
  padding: 14px 32px 20px;
  display: flex; align-items: center; justify-content: flex-end; gap: 12px;
  border-top: 1px solid #e2e8f0;
  background: #f8fafc;
  border-radius: 0 0 8px 8px;
}
.fta-rn-cta {
  background: var(--fta-navy);
  color: #fff;
  border: none;
  border-radius: 4px;
  padding: 9px 18px;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}
.fta-rn-cta:hover { background: #1a2856; }

/* Sidebar footer 'What's new' link (matches both new .sidebar-meta and legacy .sidebar-version markup).
   Near-white text on a pink underline: pink TEXT was 3.9:1 on the navy at 11px, under
   WCAG AA's 4.5:1. The underline keeps the brand cue and marks it as a link. */
.sidebar-meta a.sidebar-whats-new,
.sidebar-version a.sidebar-whats-new {
  color: var(--text-primary);
  text-decoration: underline;
  text-decoration-color: var(--fta-pink);
  text-underline-offset: 2px;
  font-weight: 600;
  cursor: pointer;
}
.sidebar-meta a.sidebar-whats-new:hover,
.sidebar-version a.sidebar-whats-new:hover { color: var(--text-active); }

/* ──────────────────────────────────────────────────────────────────
   Related Records card — vertical list at top of side panel
   Populated by JS from GET /api/quote-engine/policies/:id/timeline.
   ────────────────────────────────────────────────────────────────── */
.related-records-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.related-records-row {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 8px;
  padding: 7px 9px;
  border-radius: 6px;
  border: 1px solid var(--body-border, #e2e8f0);
  background: #fff;
  text-decoration: none;
  color: var(--body-text, #1e293b);
  font-size: 12px;
}
.related-records-row:hover {
  background: var(--body-surface-alt, #f8fafc);
}
.related-records-row.is-current {
  border-color: var(--fta-pink, #e6007e);
  box-shadow: 0 0 0 1px var(--fta-pink, #e6007e) inset;
}
.related-records-row .rr-kind {
  font-weight: 600;
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 11.5px;
  color: var(--fta-navy, #0a192f);
}
.related-records-row.is-current .rr-kind {
  color: var(--fta-pink, #e6007e);
}
.related-records-row .rr-label {
  color: #64748b;
  font-size: 11px;
}
.related-records-row .rr-status {
  font-size: 10.5px;
  padding: 2px 7px;
  border-radius: 999px;
  background: var(--body-surface-alt, #f8fafc);
  color: #475569;
  font-weight: 500;
}
/* Source-of-truth badge — sits between the row label and the status pill.
   Today only used by the SF-history backfill: the row was materialised
   from the Salesforce mirror (premium + dates + policy number only) and
   has no Excel rater attached. Subtle blue tint so the row reads as
   "factual reference" rather than alarm. */
.related-records-row .rr-source-badge {
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.04em;
  padding: 1px 6px;
  border-radius: 999px;
  text-transform: uppercase;
}
.related-records-row .rr-source-sf {
  background: rgba(37, 99, 235, 0.08);
  color: #1d4ed8;
  border: 1px solid rgba(37, 99, 235, 0.18);
}
/* MTA badge — marks a policy version minted by a mid-term adjustment, so the
   endorsement-created row is distinguishable from the original bound version.
   FTA-pink tint to echo the queue's MTA type chip. */
.related-records-row .rr-source-mta {
  background: rgba(232, 6, 140, 0.08);
  color: #be0570;
  border: 1px solid rgba(232, 6, 140, 0.20);
}
.related-records-shared-hint {
  display: inline-block;
  font-size: 10.5px;
  color: var(--text-section, #94a8d0);
  font-weight: 500;
  margin-top: 2px;
}
/* Renewal-year groups inside the Related Records card. Each group is one
   policy period — the current year sits at the top (server orders by
   policy_inception DESC), prior years stack below. */
.rr-group {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.rr-group + .rr-group {
  padding-top: 8px;
  margin-top: 4px;
  border-top: 1px dashed #e2e8f0;
}
.rr-group-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 2px 2px;
}
.rr-group-label {
  font-size: 10.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: #475569;
}
.rr-group.is-current-group .rr-group-label {
  color: var(--fta-pink, #e6007e);
}
.rr-group-current {
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.06em;
  color: var(--fta-pink, #e6007e);
  background: rgba(230, 0, 126, 0.08);
  padding: 1px 6px;
  border-radius: 999px;
}
.rr-group-rows {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
/* A single record (quote or endorsement) and its embedded version-snapshot
   list. The snapshots replace the standalone "Version History" card that
   was removed in the Phase-2 endorsement redesign — every save / status
   transition / broker send for the parent record renders inline here. */
.rr-record {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.rr-snapshots {
  list-style: none;
  margin: 0;
  padding: 4px 0 2px 14px;
  border-left: 1px dashed #e2e8f0;
  display: flex;
  flex-direction: column;
  gap: 3px;
  font-size: 11px;
  color: #475569;
}
.rr-snapshots-extra {
  border-left: none;
  padding-left: 0;
  margin-top: 3px;
}
.rr-snap-row {
  display: grid;
  grid-template-columns: auto auto 1fr auto auto;
  align-items: baseline;
  gap: 6px;
  padding: 1px 4px;
}
.rr-snap-version {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: 10.5px;
  color: var(--fta-navy, #0a192f);
  font-weight: 600;
}
.rr-snap-kind {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: #94a3b8;
  font-weight: 600;
}
.rr-snap-summary {
  color: #475569;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.rr-snap-time {
  font-size: 10.5px;
  color: #94a3b8;
  white-space: nowrap;
}
.rr-snap-sent {
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.05em;
  color: #0f766e;
  background: rgba(15, 118, 110, 0.08);
  padding: 1px 5px;
  border-radius: 999px;
}
.rr-snap-toggle {
  list-style: none;
  padding: 2px 0 0 4px;
}
.rr-snap-more {
  font-size: 10.5px;
  color: var(--fta-pink, #e6007e);
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  font-weight: 600;
}
.rr-snap-more:hover {
  text-decoration: underline;
}
.rr-empty {
  font-size: 11.5px;
  color: #94a3b8;
  padding: 6px 4px;
  font-style: italic;
}

/* ──────────────────────────────────────────────────────────────────
   Endorsement-mode premium card
   `.split-premium-card.is-endorsement` toggled by quoteapp-endorsement-page.js
   when kind=endorsement. Teal accent (#0891b2) clearly distinguishes from
   the standard pink quote-current accent.
   ────────────────────────────────────────────────────────────────── */
.split-premium-card.is-endorsement {
  border-color: #0891b2;
  box-shadow: 0 0 0 1px rgba(8, 145, 178, 0.18) inset;
}
.split-premium-card.is-endorsement .split-sum-card-title,
.split-premium-card.is-endorsement .split-prem-title {
  color: #0891b2;
}
.endorsement-prem-row {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: 4px 12px;
  padding: 8px 10px;
  border-radius: 8px;
  border: 1px solid var(--body-border, #e2e8f0);
  background: #fff;
  align-items: center;
  font-size: 12.5px;
}
.endorsement-prem-row + .endorsement-prem-row {
  margin-top: 6px;
}
.endorsement-prem-row .epr-label {
  font-weight: 600;
  color: var(--body-text, #1e293b);
  grid-column: 1 / 2;
}
.endorsement-prem-row .epr-sub {
  grid-column: 1 / 3;
  font-size: 10.5px;
  color: #64748b;
  font-weight: 400;
  margin-top: 2px;
}
.endorsement-prem-row .epr-value {
  grid-column: 3 / 4;
  font-family: var(--font-mono, ui-monospace, monospace);
  font-weight: 700;
  text-align: right;
  white-space: nowrap;
}
.endorsement-prem-row.is-delta {
  background: rgba(8, 145, 178, 0.06);
  border-color: rgba(8, 145, 178, 0.45);
}
.endorsement-prem-row.is-delta .epr-label,
.endorsement-prem-row.is-delta .epr-value {
  color: #0891b2;
}
.endorsement-prem-row.is-total {
  background: var(--fta-navy, #0a192f);
  border-color: var(--fta-navy, #0a192f);
}
.endorsement-prem-row.is-total .epr-label,
.endorsement-prem-row.is-total .epr-value {
  color: #ffffff;
}
.endorsement-prem-row.is-total .epr-sub {
  color: rgba(255, 255, 255, 0.7);
}
#premium-tabs-select.is-endorsement-options {
  max-width: 260px;
}
.endorsement-prem-breakdown {
  margin-top: 12px;
  padding-top: 10px;
  border-top: 1px dashed var(--body-border, #e2e8f0);
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 4px 12px;
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: 11.5px;
  color: #475569;
}
.endorsement-prem-breakdown-header {
  grid-column: 1 / -1;
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: #94a3b8;
  font-weight: 700;
  margin-top: 6px;
}
.endorsement-prem-auto-refer {
  display: inline-block;
  margin-top: 8px;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 700;
  background: #fef3c7;
  color: #92400e;
  border: 1px solid #fcd34d;
}

/* Editable cells in Limit Options table (Quoted, Policy Fee). */
.fta-editable-cell {
  border: 1px dashed rgba(230, 0, 126, 0.35);
  background: transparent;
  border-radius: 4px;
  padding: 2px 4px;
  text-align: right;
  font-family: var(--font-mono, ui-monospace, monospace);
  color: var(--fta-pink, #e6007e);
}
.fta-editable-cell:hover {
  border-style: solid;
  border-color: var(--fta-pink, #e6007e);
  background: rgba(230, 0, 126, 0.05);
}
.fta-editable-cell:focus {
  border-style: solid;
  border-color: var(--fta-pink, #e6007e);
  background: #fff;
  outline: none;
}
.fta-editable-cell--stale,
.fta-editable-cell--stale:hover,
.fta-editable-cell--stale:focus {
  border-style: solid;
  border-color: #f59e0b;
  background: rgba(245, 158, 11, 0.08);
}
.fta-fee-reset {
  font-size: 0.625rem;
  color: #64748b;
  text-decoration: underline;
  cursor: pointer;
  display: block;
  margin-top: 2px;
  text-align: right;
  background: none;
  border: none;
  padding: 0;
  font-family: inherit;
}
.fta-fee-reset:hover {
  color: #1e293b;
}
.fta-fee-flip {
  font-size: 0.625rem;
  color: #b45309;
  text-decoration: underline;
  cursor: pointer;
  display: block;
  margin-top: 2px;
  text-align: right;
  background: none;
  border: none;
  padding: 0;
  font-family: inherit;
}
.fta-fee-flip:hover {
  color: #78350f;
}

/* ── AI-fill marker (Stream B / B6) ───────────────────────────────────── */
/*
 * Applied by quote-editor-provenance.js to any input whose data-field-path
 * has a latest provenance row with source = 'ai_underwriter'. Cleared
 * automatically when the human saves a new value (the PUT /quotes/:id route
 * appends a 'human_entry' row, superseding the AI row).
 */
.field--ai-filled {
  border-bottom: 2px solid var(--ai-fill-marker) !important;
  background-color: var(--ai-fill-marker-soft);
}
.field--ai-filled:focus,
.field--ai-filled[data-provenance-open] {
  outline: 2px solid var(--ai-fill-marker);
  outline-offset: 1px;
}
.ai-provenance-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1rem;
  height: 1rem;
  margin-left: 4px;
  border-radius: 50%;
  background: var(--ai-fill-marker);
  color: #fff;
  font-size: 0.625rem;
  font-weight: 600;
  cursor: pointer;
  user-select: none;
  vertical-align: middle;
}
.ai-provenance-badge:hover { filter: brightness(1.08); }

/* Frankie mark — shared square badge for "Ask Frankie" affordances (nav CTA,
 * dashboard/record CTAs, proposal-form floating button, editor v2 header
 * button). Sourced from the Frankie Teams bot icon
 * (functions/notifications-bot/teams-manifest/color.png — white unicorn on
 * FTA navy) copied verbatim to /images/frankie-icon.png, replacing the older,
 * rougher potrace-vectorised inline SVG unicorn glyph the buttons used to
 * carry individually. A raster logo mark (not currentColor-recolourable like
 * the old SVGs), so it renders as a small navy tile rather than matching the
 * button's text colour — same pattern as showing a bot's own logo next to
 * "Ask <bot>" copy. Width/height set per call site to match prior icon sizing. */
.frankie-icon {
  display: inline-block;
  flex-shrink: 0;
  border-radius: 3px;
  vertical-align: middle;
}

/* "Changes from last year" — indigo left-border (renewal adopt). A SEPARATE
 * layer from the amber AI-fill / pink V2 markers: quote-editor-provenance.js
 * adds this independently, so a field can show the AI marker AND the prior-year
 * marker at once. Left-border keeps it visually distinct from the amber
 * underline + pink full-border. */
.field--changed-last-year {
  border-left: 3px solid var(--prior-year-accent, #6366f1) !important;
  background-color: var(--prior-year-accent-soft, rgba(99, 102, 241, 0.06));
}
.field--changed-last-year:focus {
  outline: 2px solid var(--prior-year-accent, #6366f1);
  outline-offset: 1px;
}
/* Compose with the AI markers — keep each marker's own edge so both read. */
.field--ai-filled.field--changed-last-year {
  border-bottom: 2px solid var(--ai-fill-marker) !important;
  border-left: 3px solid var(--prior-year-accent, #6366f1) !important;
}
.field--low-confidence.field--changed-last-year {
  border-color: var(--status-warning, #f59e0b);
  border-left: 3px solid var(--prior-year-accent, #6366f1) !important;
}

/* R3 · V2 editor variant — pink outline + Frankie glyph ─────────────────
 * The QuoteApp V2 editor sets window.QA_UI_V2; quote-editor-provenance.js
 * adds the `--v2` classes below only on V2, so the classic editor keeps the
 * amber underline + circled "i" above, untouched. Same provenance data + JS;
 * only the marker's look changes on V2. */
.field--ai-filled-v2 {
  /* Thin pink border hugging the field. The grey border comes from
     `.split-page .split-input` (0,2,0) which outranks this class, and the V2
     CSS zeroes `outline`, so recolour the border itself with !important.
     The shared `.field--ai-filled` rule (classic) also forces a 2px amber
     `border-bottom !important`; pull that back to a uniform 1px pink here. */
  border-color: var(--fta-pink, #e6007e) !important;
  border-bottom-width: 1px !important;
  background-color: rgba(230, 0, 126, 0.05);
}
/* Positioning context for the corner badge — the marker JS adds this to the
   marked input's parent so the Frankie glyph can sit on the field's top-right
   corner regardless of how that particular field is wrapped. */
.field--ai-anchor { position: relative; }
.ai-provenance-badge--v2 {
  position: absolute;
  top: -7px;
  right: -7px;
  z-index: 2;
  width: 16px;
  height: 16px;
  margin: 0;
  padding: 0;
  background: var(--fta-pink, #e6007e);
  color: #fff;
  box-shadow: 0 1px 3px rgba(15, 23, 42, 0.25);
}
.ai-provenance-badge--v2 svg { display: block; width: 10px; height: 10px; }
.ai-provenance-badge--v2:hover { filter: brightness(1.08); }

/* UAT 10.7 · "Changed by broker" marker (mig 524) ────────────────────────
 * quote-editor-provenance.js applies these when the LATEST provenance row
 * for a field is source 'broker_portal' (broker edited + resubmitted a
 * reopened submission). Teal — deliberately distinct from the AI amber
 * (classic), AI pink (V2), and prior-year indigo — with a circled "B"
 * badge in both editors. Clears exactly like the AI marker: a UW save
 * appends a 'human' supersede row, which becomes latest on next load. */
.field--broker-changed {
  border-bottom: 2px solid var(--broker-change-marker) !important;
  background-color: var(--broker-change-marker-soft);
}
.field--broker-changed:focus,
.field--broker-changed[data-provenance-open] {
  outline: 2px solid var(--broker-change-marker);
  outline-offset: 1px;
}
/* V2 editor variant — full teal border hugging the field, mirroring the
 * pink `.field--ai-filled-v2` treatment (same specificity notes apply). */
.field--broker-changed-v2 {
  border-color: var(--broker-change-marker) !important;
  border-bottom-width: 1px !important;
  background-color: var(--broker-change-marker-soft);
}
/* Recolour the shared badge (classic inline circle OR V2 corner square). */
.ai-provenance-badge--broker {
  background: var(--broker-change-marker);
}
/* Compose with the prior-year indigo left border, same as the AI marker. */
.field--broker-changed.field--changed-last-year {
  border-bottom: 2px solid var(--broker-change-marker) !important;
  border-left: 3px solid var(--prior-year-accent, #6366f1) !important;
}
/* The lineage popover is appended to <body>, outside the editor, so it can't
 * read a V2 ancestor class; its heading keeps the shared amber accent — the
 * pink border + corner Frankie badge are what read as "Frankie filled this". */
.ai-provenance-popover {
  position: absolute;
  z-index: 1200;
  max-width: 320px;
  min-width: 220px;
  padding: 12px 14px;
  background: #fff;
  color: var(--body-text);
  border: 1px solid var(--body-border);
  border-radius: 8px;
  box-shadow: 0 12px 28px -12px rgba(15, 23, 42, 0.25);
  font-size: 0.75rem;
  line-height: 1.45;
}
.ai-provenance-popover h4 {
  margin: 0 0 6px;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--ai-fill-marker);
}
.ai-provenance-popover dl { margin: 4px 0 0; }
.ai-provenance-popover dt {
  font-weight: 600;
  font-size: 0.6875rem;
  color: var(--body-text-label);
  margin-top: 6px;
}
.ai-provenance-popover dd { margin: 0; word-break: break-word; }
/* Source pill — mirrors the AInbox extracted-fields source chip so the
 * popover tells the underwriter WHERE a value came from (📧 body / 📎
 * attachment / 🧵 thread / 🤖 inferred / ✋ human). */
.ai-provenance-popover .source-pill {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  max-width: 100%;
  padding: 2px 8px;
  border: 1px solid var(--body-border);
  border-radius: 999px;
  background: var(--surface-muted, #f8fafc);
  font-size: 0.6875rem;
  color: var(--body-text);
}
.ai-provenance-popover .source-pill__icon { line-height: 1; }
.ai-provenance-popover .source-pill__label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ai-provenance-popover .prov-value {
  margin-top: 6px;
  font-weight: 600;
  word-break: break-word;
}
.ai-provenance-popover .prov-citation {
  margin-top: 6px;
  font-size: 0.6875rem;
  color: var(--body-text-label);
  word-break: break-word;
}
.ai-provenance-popover .timestamp {
  margin-top: 8px;
  font-size: 0.6875rem;
  color: var(--text-dim);
}

/* ── "Why did this change?" capture (V2 editor) ──────────────────────
 * quote-editor-field-reason.js. A tiny, dismissible chip that appears next
 * to an AI-touched field the user just overrode, plus a two-tier popover
 * (reuses .ai-provenance-popover above). Minimalist + optional — brand pink
 * to read as "teach Frankie", never a blocking control. */
.field-reason-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin: 4px 0 0 6px;
  padding: 2px 8px;
  border: 1px solid var(--fta-pink, #e6007e);
  border-radius: 999px;
  background: rgba(230, 0, 126, 0.06);
  color: var(--fta-pink, #e6007e);
  font-size: 0.6875rem;
  font-weight: 600;
  line-height: 1.3;
  cursor: pointer;
  transition: background-color 0.12s ease;
}
.field-reason-chip:hover { background: rgba(230, 0, 126, 0.12); }
.field-reason-chip--done {
  border-color: var(--body-border);
  background: var(--surface-muted, #f8fafc);
  color: var(--body-text-label);
  cursor: default;
}
.field-reason-chip__x {
  font-size: 0.625rem;
  line-height: 1;
  opacity: 0.6;
}
.field-reason-chip__x:hover { opacity: 1; }
.field-reason-popover h4 { color: var(--fta-pink, #e6007e); }
.field-reason-choices {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 8px;
}
.field-reason-choices--stack { flex-direction: column; }
.field-reason-choice {
  padding: 4px 10px;
  border: 1px solid var(--body-border);
  border-radius: 6px;
  background: #fff;
  color: var(--body-text);
  font-size: 0.6875rem;
  font-weight: 500;
  text-align: left;
  cursor: pointer;
  transition: border-color 0.12s ease, background-color 0.12s ease;
}
.field-reason-choice:hover {
  border-color: var(--fta-pink, #e6007e);
  background: rgba(230, 0, 126, 0.06);
}
.field-reason-note-row { margin-top: 8px; }
.field-reason-note {
  width: 100%;
  padding: 4px 8px;
  border: 1px solid var(--body-border);
  border-radius: 6px;
  font-size: 0.6875rem;
  color: var(--body-text);
  outline: none;
}
.field-reason-note:focus { border-color: var(--fta-pink, #e6007e); }

/* ── Broker-facing variant (PR-18) ───────────────────────────────────
 * Sibling of .field--ai-filled / .ai-provenance-* used by the internal
 * Quote Editor. Same amber underline so brokers can see AI-touched
 * fields, but the popover stays polite + terse — no evidenceKind dump,
 * no "teach the AI" CTA. Driven by broker-extracted-fields.js. */
/* Item 8 — broker-facing AI/pre-filled fields use brand PINK so they read
   clearly as "FTA AI filled this", not a greyed-out/disabled field. The
   internal editor (quote-editor-provenance, .field--ai) keeps the amber
   --ai-fill-marker; only the broker portal is overridden to pink here. */
.field--ai-broker {
  border-bottom: 2px solid var(--fta-pink, #e6007e) !important;
  background-color: rgba(230, 0, 126, 0.07);
}
.field--ai-broker:focus,
.field--ai-broker[data-broker-provenance-open] {
  outline: 2px solid var(--fta-pink, #e6007e);
  outline-offset: 1px;
}
.ai-broker-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 1rem;
  padding: 0 5px;
  margin-left: 4px;
  border-radius: 999px;
  background: var(--fta-pink, #e6007e);
  color: #fff;
  font-size: 0.625rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  cursor: pointer;
  user-select: none;
  vertical-align: middle;
}
.ai-broker-badge:hover { filter: brightness(1.08); }
.ai-broker-popover {
  position: absolute;
  z-index: 1200;
  max-width: 280px;
  min-width: 180px;
  padding: 10px 12px;
  background: #fff;
  color: var(--body-text);
  border: 1px solid var(--body-border);
  border-radius: 8px;
  box-shadow: 0 12px 28px -12px rgba(15, 23, 42, 0.25);
  font-size: 0.75rem;
  line-height: 1.45;
}
.ai-broker-popover-heading {
  display: block;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--fta-pink, #e6007e);
  margin-bottom: 4px;
}
.ai-broker-popover-note {
  margin: 0;
  color: var(--body-text);
  font-size: 0.6875rem;
  line-height: 1.45;
}

/* ──────────────────────────────────────────────────────────────────
 * AInbox debug-id pills (renderDebugIdPills in enquiry-management.js)
 * Small mono UUID + graph-id chips in the email detail-pane header.
 * Click to copy. Unobtrusive — dimmed by default, slight emphasis on
 * hover. Uses existing tokens; no hardcoded px.
 * ──────────────────────────────────────────────────────────────── */
.debug-id-row {
  display: flex;
  gap: var(--space-xs);
  margin-top: var(--space-xs);
  flex-wrap: wrap;
}
.debug-id-pill {
  display: inline-flex;
  align-items: center;
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  color: var(--text-dim);
  padding: var(--space-xs) var(--space-sm, 8px);
  border-radius: var(--radius-sm);
  background: rgba(148, 163, 184, 0.08);
  cursor: pointer;
  /* D11: the pill is click-to-copy, but staff also need to manually
     select the id (e.g. to paste into a SQL WHERE clause or a specific
     field). `user-select: none` blocked that — the 2026-05-19 ask was
     literally "id needs to be selectable, copyable". `all` selects the
     entire id on a single click without a precise drag. */
  user-select: all;
  -webkit-user-select: all;
  white-space: pre;
  transition: color 120ms ease, background 120ms ease;
}
.debug-id-pill:hover {
  color: var(--text-primary);
  background: rgba(148, 163, 184, 0.16);
}
.debug-id-pill-copied {
  color: var(--text-primary);
  background: rgba(72, 187, 120, 0.18);
}

/* SF pending pill — applied to the QuoteApp "Linked: SF Opportunity" badge
   when the row's sf_opportunity_id is a LOCAL- sentinel (SF was skipped
   or failed). Toggled via .classList.toggle('sf-pending-pill', isLocal)
   in quoteapp-core.js so re-renders can't leave amber paint behind. */
.sf-pending-pill {
  background: #fefce8 !important;
  border-color: #fde047 !important;
}
.sf-pending-pill > span,
.sf-pending-pill > a {
  color: #a16207 !important;
  cursor: default;
  text-decoration: none;
}

/* ── Shared inline email-body typography (FTAEmailDoc.renderInline) ───────────
   The ONE rule for an email body rendered inline (no iframe) into a host that
   carries `.fta-email-body` — My Work action drawer, AInbox editor panel, etc.
   Gives a plaintext-or-HTML body consistent reading formatting everywhere. */
.fta-email-body { font-size: 13px; line-height: 1.55; color: #1f2937; word-break: break-word; }
.fta-email-body > :first-child { margin-top: 0; }
.fta-email-body > :last-child { margin-bottom: 0; }
.fta-email-body p { margin: 0 0 0.7em; }
.fta-email-body ul, .fta-email-body ol { margin: 0 0 0.7em; padding-left: 1.25rem; }
.fta-email-body li { margin: 0.15em 0; }
.fta-email-body h1, .fta-email-body h2, .fta-email-body h3,
.fta-email-body h4, .fta-email-body h5, .fta-email-body h6 { font-size: 13.5px; margin: 0.9em 0 0.4em; color: var(--fta-navy, #0a192f); }
.fta-email-body a { color: var(--ai-blue, #2563eb); }
.fta-email-body blockquote { margin: 0 0 0.7em; padding: 0 0 0 0.75rem; border-left: 3px solid #e2e8f0; color: #475569; }
.fta-email-body img { max-width: 100%; height: auto; }
.fta-email-body table { border-collapse: collapse; max-width: 100%; font-size: 12.5px; }
.fta-email-body th, .fta-email-body td { border: 1px solid #e6e8ef; padding: 4px 8px; text-align: left; }
.fta-email-body hr { border: 0; border-top: 1px solid #e6e8ef; margin: 0.8em 0; }
/* Plaintext bodies: preserve newlines/spacing so they don't collapse to a wall. */
.fta-email-body .fta-email-pre, .fta-email-pre { margin: 0; white-space: pre-wrap; word-wrap: break-word; font: inherit; }

/* ── Shared three-view attachment viewer (attachment-viewer.js) ──────────────
   Rendered inside the AInbox read panel and the central email modal — both
   light-surface contexts, so these use explicit neutral colours rather than
   the dark :root tokens. Original / Plain text / Templated tabs per file. */
.fta-att-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.5rem; }
.fta-att-empty { color: #64748b; font-size: 0.8125rem; margin: 0.25rem 0; }
.fta-att {
  border: 1px solid #e2e8f0;
  border-radius: 8px;
  background: #fff;
  overflow: hidden;
}
.fta-att-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 0.5rem; padding: 0.5rem 0.625rem; border-bottom: 1px solid #f1f5f9;
}
.fta-att-name { font-weight: 600; font-size: 0.8125rem; color: #0f172a; word-break: break-word; }
.fta-att-status { color: #64748b; font-size: 0.6875rem; text-transform: uppercase; letter-spacing: 0.03em; }
.fta-att-tabs { display: flex; gap: 0.25rem; padding: 0.375rem 0.625rem 0; }
.fta-att-tab {
  border: 1px solid #e2e8f0; background: #f8fafc; color: #475569;
  font-size: 0.75rem; padding: 0.25rem 0.625rem; border-radius: 6px; cursor: pointer;
}
.fta-att-tab[data-active="1"] {
  background: var(--fta-pink, #e6007e); border-color: var(--fta-pink, #e6007e); color: #fff;
}
.fta-att-body { padding: 0.5rem 0.625rem 0.625rem; }
.fta-att-pane { font-size: 0.8125rem; color: #1e293b; }
.fta-att-raw {
  white-space: pre-wrap; word-break: break-word; font-size: 0.75rem;
  background: #f8fafc; border: 1px solid #f1f5f9; border-radius: 6px;
  padding: 0.5rem; margin: 0; max-height: 360px; overflow: auto;
}
.fta-att-rendered { max-height: 420px; overflow: auto; }
.fta-att-rendered table { border-collapse: collapse; width: 100%; }
.fta-att-rendered th, .fta-att-rendered td { border: 1px solid #e2e8f0; padding: 0.25rem 0.5rem; text-align: left; }
.fta-att-original { display: flex; flex-direction: column; gap: 0.5rem; }
.fta-att-open { color: var(--fta-pink, #e6007e); font-size: 0.75rem; text-decoration: underline; }
.fta-att-frame { width: 100%; height: 420px; border: 1px solid #e2e8f0; border-radius: 6px; background: #fff; }
.fta-att-generate {
  border: 1px solid var(--fta-pink, #e6007e); background: #fff; color: var(--fta-pink, #e6007e);
  font-size: 0.75rem; padding: 0.375rem 0.75rem; border-radius: 6px; cursor: pointer;
}
.fta-att-generate:hover { background: var(--fta-pink, #e6007e); color: #fff; }

/* ── Portfolio scope toggle ──────────────────────────────────────────────── */
/* Pill-style button group shared across Broker Houses, Broker Map, Visit
   Planner. Active state uses brand navy; inactive is muted grey.
   JS adds/removes .active-scope per button. */
.scope-toggle {
  display: inline-flex;
  align-items: center;
  border: 1px solid var(--border-color, #e2e8f0);
  border-radius: 8px;
  overflow: hidden;
  background: #fff;
}
.scope-toggle [data-scope] {
  padding: 6px 14px;
  font-size: 0.8125rem;
  font-weight: 500;
  color: #64748b;
  background: transparent;
  border: none;
  cursor: pointer;
  line-height: 1.4;
  transition: background 0.15s, color 0.15s;
}
.scope-toggle [data-scope]:not(:last-child) {
  border-right: 1px solid var(--border-color, #e2e8f0);
}
.scope-toggle [data-scope]:hover:not(.active-scope) {
  background: #f8fafc;
  color: #334155;
}
.scope-toggle [data-scope].active-scope {
  background: var(--fta-navy);
  color: #fff;
}

/* Shared "open in new window" button (window.FTAPopout) — used by every
   document/attachment viewer header so the affordance looks identical
   everywhere. Subtle icon button; navy on hover. */
.fta-popout-btn {
  width: 28px;
  height: 28px;
  display: inline-grid;
  place-items: center;
  border: none;
  background: transparent;
  color: #64748b;
  border-radius: 6px;
  cursor: pointer;
  padding: 0;
  line-height: 1;
}
.fta-popout-btn:hover {
  background: rgba(15, 23, 42, 0.06);
  color: var(--fta-navy, #0a192f);
}
.fta-popout-btn svg {
  width: 14px;
  height: 14px;
  display: block;
}

/* Internal-only "Ubind" marker on the QuoteApp detail header — quotes imported
   from the weekly Ubind transaction report (source_type='ubind_history').
   Staff-facing only; never rendered on broker/customer surfaces. */
.hdr-ubind-badge {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 7px;
  border-radius: 999px;
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  vertical-align: middle;
  color: var(--fta-pink, #e6007e);
  background: var(--accent-badge-bg, rgba(230, 0, 126, 0.18));
}

/* Internal-only "Test" marker beside the quote ID on the QuoteApp editor header —
   a PVT test quote (isTest). The TEST MODE banner shouts; this only labels, so it
   is the same amber as a soft chip. Staff-facing only; never on broker surfaces. */
.hdr-test-badge {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 7px;
  border: 1px solid var(--status-warning-line);
  border-radius: var(--radius-full);
  font-size: var(--font-size-xs);
  font-weight: var(--font-weight-bold);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  vertical-align: middle;
  color: var(--status-warning-text);
  background: var(--status-warning-bg);
}

/* ── Filter chips (reporting surfaces) ───────────────────────────────────
   Multi-select filter pills used by Product Dashboards and My Portfolio.
   Lifted out of product-dashboards.html when My Portfolio gained a product
   filter, so the two pages cannot drift on chip styling.

   SCOPED to `.chip-row` deliberately. `.chip` is already used as a plain,
   non-interactive label class elsewhere (admin-anzsic-classifier's
   classification badges, sanctions' list-snapshot chips), and global.css loads
   on every page — an unscoped rule gave those static labels a border and a
   pointer cursor. Both reporting pages always nest chips in `.chip-row`, so
   scoping costs nothing here. */
.chip-row .chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 12px; font-size: 13px; font-weight: 500;
  border-radius: 9999px; cursor: pointer; user-select: none;
  background: var(--body-surface-alt); color: var(--body-text-label);
  border: 1px solid var(--body-border);
  transition: background 0.12s, color 0.12s, border-color 0.12s;
}
.chip-row .chip:hover { background: var(--body-border); }
/* Navy fill, not pink-on-wash. `--fta-pink` over `--accent-bg` measures ~3.8:1
   at 13px/600 and fails WCAG AA; navy/white is ~17:1, and DESIGN-SYSTEM-RULES
   already prescribes navy for a resting selected state. Shared with My
   Portfolio — verify both pages after touching this. */
.chip-row .chip.active {
  background: var(--fta-navy); color: var(--text-active);
  border-color: var(--fta-navy); font-weight: 600;
}
/* The product dot keeps its own hue on the navy fill; a hairline ring stops a
   dark product colour (PI is navy) disappearing into the chip. */
.chip-row .chip.active .chip-dot { box-shadow: 0 0 0 1px var(--slate-300); }
/* The chips are real <button role="checkbox"> elements on Product Dashboards,
   so they inherit a UA button font. Keep them on the body face. */
.chip-row button.chip { font-family: inherit; }
.chip-row .chip:focus-visible { outline: 2px solid var(--fta-action-blue-focus); outline-offset: 1px; }
.chip-row .chip-dot { width: 10px; height: 10px; border-radius: 9999px; }
.chip-row { display: flex; flex-wrap: wrap; gap: 6px; }

.filter-group { display: flex; flex-direction: column; gap: 6px; }
.filter-label {
  font-size: 11px; font-weight: 600; text-transform: uppercase;
  letter-spacing: 0.04em; color: var(--body-text-muted);
}

/* ── Per-card Excel download (reporting surfaces) ─────────────────────────
   The "Excel" link in each card's header on Product Dashboards and My
   Portfolio. Lifted out of product-dashboards.html when My Portfolio gained
   per-card downloads, for the same reason as the chips above. Quiet until
   hovered — a page of these must not read as a page of calls to action. */
.card-dl { display: inline-flex; align-items: center; gap: 4px;
  padding: 4px 8px; border: 1px solid transparent; border-radius: var(--radius-sm);
  background: transparent; font-family: var(--font-body); font-size: var(--font-size-xs);
  color: var(--body-text-muted); cursor: pointer;
  transition: background var(--transition-fast), color var(--transition-fast),
              border-color var(--transition-fast); }
.card-dl:hover { background: var(--body-surface-alt); border-color: var(--body-border);
  color: var(--body-text-label); }
.card-dl:focus-visible { outline: 2px solid var(--fta-action-blue-focus); outline-offset: 1px; }
.card-dl[disabled] { opacity: .5; cursor: progress; }
.card-dl svg { width: 13px; height: 13px; }

/* ── @mention picker + rendered mentions (mig 549) ──────────────────────
   Used by js/mention-input.js on every comment box, and by the rendered
   comment body in js/comments-thread.js. Tokens only — no literals — so
   the css-token baseline stays put. */
.mention {
  color: var(--fta-pink);
  font-weight: 600;
}

.mention-menu {
  position: absolute;
  z-index: var(--z-dropdown);
  min-width: 220px;
  max-width: 320px;
  max-height: 216px;
  overflow-y: auto;
  background: var(--body-surface);
  border: 1px solid var(--body-border);
  border-radius: var(--radius-sm);
  box-shadow: var(--agent-ui-shadow);
  padding: var(--space-xs) 0;
  font-family: var(--font-body);
}
.mention-menu[hidden] { display: none; }

.mention-option {
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: 6px var(--space-sm);
  cursor: pointer;
  font-size: 13px;
  color: var(--body-text);
}
.mention-option:hover,
.mention-option[aria-selected="true"] {
  background: var(--body-surface-alt);
}
.mention-option .mention-option-name { font-weight: 600; }
.mention-option .mention-option-meta {
  font-size: 11px;
  color: var(--body-text-muted);
}
.mention-empty {
  padding: 6px var(--space-sm);
  font-size: 12px;
  color: var(--body-text-muted);
}

/* ==========================================================================
   Quote drawer (quote-drawer.js)
   --------------------------------------------------------------------------
   The right-hand slide-over every Portfolio aggregate opens into. Same shell
   the /broker-map and /broker-house-scores `.detail-panel` drawers use —
   translateX off-canvas, `--z-drawer` so Leaflet (panes 400, controls 1000)
   cannot draw over it — lifted here so the three cannot drift apart.
   ========================================================================== */
:root {
  /* Drawer-only colours, as tokens rather than literals so the css-tokens lint
     stays clean and a theme change has one place to reach. Slate-900 at low
     alpha is the scrim the QuoteApp drawers already read as. */
  --qd-scrim: rgba(15, 23, 42, 0.35);
  --qd-shadow: -8px 0 24px rgba(15, 23, 42, 0.12);
  --qd-focus-ring: 0 0 0 3px rgba(230, 0, 126, 0.12);
}

.qd-overlay {
  position: fixed;
  inset: 0;
  background: var(--qd-scrim);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease;
  z-index: var(--z-overlay);
}
.qd-overlay.open { opacity: 1; pointer-events: auto; }

.qd-panel {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  width: 30rem;
  max-width: 100vw;
  display: flex;
  flex-direction: column;
  background: var(--body-surface);
  border-left: 1px solid var(--body-border);
  box-shadow: var(--qd-shadow);
  transform: translateX(100%);
  transition: transform 0.3s ease;
  z-index: var(--z-drawer);
}
.qd-panel.open { transform: translateX(0); }
@media (max-width: 768px) { .qd-panel { width: 100%; } }
/* The panel takes focus on open so keyboard and screen-reader users land inside
   the dialog. That focus is programmatic, not a target to point at, and the
   browser's default ring drew a dark frame around the whole drawer. The controls
   inside keep their own focus styles. */
.qd-panel:focus,
.qd-panel:focus-visible { outline: none; }

/* The page behind must not scroll under an open drawer — on touch the drawer's
   own list would otherwise hand its momentum to the body at the end of a fling. */
body.qd-open { overflow: hidden; }

.qd-head {
  display: flex;
  align-items: flex-start;
  gap: var(--space-sm);
  padding: var(--space-md);
  border-bottom: 1px solid var(--body-border);
}
.qd-titles { flex: 1; min-width: 0; }
.qd-title {
  font-size: 15px;
  font-weight: 600;
  color: var(--body-heading);
  line-height: 1.3;
}
.qd-subtitle {
  margin-top: 2px;
  font-size: 12px;
  color: var(--body-text-muted);
}
.qd-close {
  flex-shrink: 0;
  width: 28px;
  height: 28px;
  border-radius: var(--radius-sm);
  font-size: 20px;
  line-height: 1;
  color: var(--body-text-muted);
  background: transparent;
  cursor: pointer;
}
.qd-close:hover { background: var(--body-surface-alt); color: var(--body-text); }

.qd-search { padding: var(--space-sm) var(--space-md); }
.qd-search input {
  width: 100%;
  padding: 7px var(--space-sm);
  font-size: 13px;
  color: var(--body-text);
  background: var(--body-surface);
  border: 1px solid var(--body-border);
  border-radius: var(--radius-sm);
}
.qd-search input:focus {
  outline: none;
  border-color: var(--fta-pink);
  box-shadow: var(--qd-focus-ring);
}

.qd-body { flex: 1; overflow-y: auto; padding: 0 var(--space-md); }
.qd-note {
  padding: var(--space-lg) 0;
  font-size: 13px;
  color: var(--body-text-muted);
  text-align: center;
}
.qd-note--error { color: var(--status-error); }
/* What the policy states after "Bound · " mean, under the list that shows them. */
.qd-status-legend {
  margin: var(--space-sm) 0;
  font-size: var(--font-size-sm);
  line-height: 1.5;
  white-space: pre-line;
  color: var(--body-text-muted);
}

.qd-row {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  padding: 10px 0;
  border-bottom: 1px solid var(--body-border);
  text-decoration: none;
  color: inherit;
}
.qd-row:last-child { border-bottom: 0; }
a.qd-row:hover { background: var(--body-surface-alt); }
.qd-row-main { flex: 1; min-width: 0; }
.qd-row-label {
  font-size: 13px;
  font-weight: 500;
  color: var(--body-text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.qd-row-sub {
  margin-top: 1px;
  font-size: 11px;
  color: var(--body-text-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.qd-row-value {
  flex-shrink: 0;
  font-size: 13px;
  font-weight: 600;
  color: var(--body-heading);
}

/* A quote's status — the policy's once bound — as a pill. The colours are the
   version-chain vocabulary above (every pair clears 4.5:1), so a status reads
   the same way here as it does on the quote. Also used inside the league
   tables' expanded rows on Product Dashboards. */
.qd-status {
  flex-shrink: 0;
  display: inline-block;
  margin-right: 6px;
  padding: 1px 7px;
  border: 1px solid var(--vchain-draft-line);
  border-radius: 9999px;
  background: var(--vchain-draft-bg);
  color: var(--vchain-draft-fg);
  font-size: 11px;
  font-weight: 600;
  line-height: 1.5;
  white-space: nowrap;
  vertical-align: middle;
}
.qd-status[data-tone="good"] {
  border-color: var(--vchain-active-line);
  background: var(--vchain-active-bg);
  color: var(--vchain-active-fg);
}
.qd-status[data-tone="warn"] {
  border-color: var(--status-warning-line);
  background: var(--status-warning-bg);
  color: var(--status-warning-text);
}
.qd-status[data-tone="bad"] {
  border-color: var(--vchain-declined-line);
  background: var(--vchain-declined-bg);
  color: var(--vchain-declined-fg);
}
.qd-status[data-tone="muted"] {
  border-color: var(--vchain-inert-line);
  background: var(--vchain-inert-bg);
  color: var(--vchain-inert-fg);
}

.qd-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
  padding: var(--space-sm) var(--space-md);
  border-top: 1px solid var(--body-border);
}
.qd-count { font-size: 12px; color: var(--body-text-muted); }
.qd-more {
  padding: 5px 10px;
  font-size: 12px;
  font-weight: 500;
  color: var(--body-text);
  background: var(--body-surface);
  border: 1px solid var(--body-border);
  border-radius: var(--radius-sm);
  cursor: pointer;
}
.qd-more:hover:not(:disabled) { background: var(--body-surface-alt); }
.qd-more:disabled { opacity: 0.5; cursor: default; }
.qd-more.hidden { display: none; }

/* Anything that opens the drawer. The affordance has to be visible BEFORE the
   hover — a KPI tile does not read as clickable on its own. */
.qd-clickable { cursor: pointer; }
.qd-clickable:hover { background: var(--body-surface-alt); }
.qd-clickable:focus-visible {
  outline: 2px solid var(--fta-pink);
  outline-offset: 2px;
}

/* Explainer popover (the scope dropdown / basis toggle captions). */
.qd-pop {
  position: absolute;
  /* ANCHORED, not left to its static position. The popover is inserted as a
     sibling of its trigger, and its trigger lives in a flex row — an absolute
     box with no top/right there lands wherever the flex line centred it, which
     put this one 26px ABOVE the viewport and 300px past its right edge.
     Right-aligned because these controls sit at the right of the page header,
     where a left-aligned panel would run off the screen. */
  top: calc(100% + var(--space-xs));
  right: 0;
  z-index: var(--z-modal);
  width: 19rem;
  max-width: calc(100vw - 2rem);
  padding: 10px var(--space-sm);
  font-size: 12px;
  line-height: 1.5;
  color: var(--body-text);
  background: var(--body-surface);
  border: 1px solid var(--body-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow);
}
.qd-pop.hidden { display: none; }
.qd-pop strong { color: var(--body-heading); }
.qd-pop p + p { margin-top: 6px; }

.qd-info {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  border-radius: var(--radius-full);
  font-size: 11px;
  font-weight: 600;
  color: var(--body-text-muted);
  background: var(--body-surface-alt);
  border: 1px solid var(--body-border);
  cursor: pointer;
}
.qd-info:hover { color: var(--fta-pink); border-color: var(--fta-pink); }
