    /* ---------- Top tab strip ----------
       Segmented control above the report shell. Default tab = "report"
       so the page reads exactly as before. Tabs are a SOFT view filter:
       each section carries a data-tab-include list and CSS hides any
       section that isn't part of the active tab's set. The underlying
       page structure is unchanged so #anchor deep-links keep working. */
    .report-v2-tabstrip {
      display: flex; flex-wrap: wrap; gap: 4px;
      padding: 4px;
      background: var(--surface-pale-cool);
      border: 1px solid var(--border-cool);
      border-radius: 999px;
      margin-bottom: 6px;
      position: sticky; top: 14px; z-index: 5;
    }
    .report-v2-tab {
      flex: 1 1 auto;
      padding: 8px 14px;
      border-radius: 999px;
      background: transparent;
      border: 0;
      color: var(--ink-slate);
      font-size: 11px; font-weight: 800;
      letter-spacing: 0.06em; text-transform: uppercase;
      cursor: pointer;
      transition: background 0.15s ease, color 0.15s ease;
    }
    .report-v2-tab:hover { background: rgba(255, 255, 255, 0.6); color: var(--ink-navy); }
    .report-v2-tab.is-active {
      background: var(--ink-navy); color: var(--surface-cream);
      box-shadow: 0 4px 10px rgba(28, 51, 67, 0.18);
    }
    /* Tab visibility — hide any section whose data-tab-include doesn't
       contain the active tab token. `~=` matches whole space-separated
       words, so "report niche" matches both "report" and "niche". */
    .report-v2-layout[data-tab-mode="executive"] [data-tab-include]:not([data-tab-include~="executive"]) { display: none !important; }
    .report-v2-layout[data-tab-mode="report"]    [data-tab-include]:not([data-tab-include~="report"])    { display: none !important; }
    .report-v2-layout[data-tab-mode="niche"]     [data-tab-include]:not([data-tab-include~="niche"])     { display: none !important; }
    .report-v2-layout[data-tab-mode="sources"]   [data-tab-include]:not([data-tab-include~="sources"])   { display: none !important; }
    /* When the user filters to a narrow tab the rail's deep-link list
       still points at sections that are now hidden. Dim those links so
       it's obvious they're out of scope. */
    .report-v2-layout[data-tab-mode="executive"] .report-v2-rail a:not([href="#rv2-hero"]):not([href="#rv2-exec"]):not([href="#rv2-synthesis"]):not([href="#rv2-feedback"]) { opacity: 0.4; }
    .report-v2-layout[data-tab-mode="niche"]    .report-v2-rail a:not([href="#rv2-hero"]):not([href="#rv2-niche"]):not([href="#rv2-feedback"]) { opacity: 0.4; }
    .report-v2-layout[data-tab-mode="sources"]  .report-v2-rail a:not([href="#rv2-hero"]):not([href="#rv2-sources"]):not([href="#rv2-feedback"]) { opacity: 0.4; }

    /* ---------- Inline tab-jump shortcuts ----------
       "View all niche assets ›" / "Open full source package ›" — small
       chips that switch the active tab. Visible only on the Report tab
       so they don't clutter the dedicated tab views. */
    .report-v2-tab-jump {
      margin-top: 12px;
      display: flex; justify-content: flex-end;
    }
    .report-v2-tab-jump-btn {
      display: inline-flex; align-items: center; gap: 4px;
      padding: 6px 14px; border-radius: 999px;
      background: var(--surface-white); border: 1px solid var(--border-cool); color: var(--ink-navy);
      font-size: 11px; font-weight: 800; letter-spacing: 0.05em;
      text-transform: uppercase; cursor: pointer;
      transition: background 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
    }
    .report-v2-tab-jump-btn:hover {
      background: var(--surface-pale-cool); border-color: var(--ink-cool-grey-pale); transform: translateY(-1px);
    }

    /* ---------- Readability polish ----------
       The Detailed Analysis is the page's heart — give the long-form
       text enough breathing room and clear section separation without
       boxing every paragraph. */
    .report-v2-detailed-list { gap: 24px; }
    .report-v2-detailed-section + .report-v2-detailed-section {
      padding-top: 18px;
      border-top: 1px dashed rgba(28, 51, 67, 0.10);
    }
    .report-v2-detailed-section { padding-left: 18px; }
    .report-v2-detailed-heading { font-size: 17px; margin-bottom: 10px; }
    .report-v2-detailed-body { font-size: 14.5px; line-height: 1.72; max-width: 760px; }
    .report-v2-detailed-body p { margin: 0 0 14px 0; }
    /* Analyst Brief reads as the opening memo — slightly larger
       paragraph spacing matches the Detailed Analysis cadence. */
    .report-v2-brief-paragraph { line-height: 1.72; margin-bottom: 14px; }

    /* ---------- Rail port from Material report ----------
       Same chrome the Material report uses: white card with rounded
       corners, soft shadow, active-state with inset left rule, nested
       sub-anchors with a small tick connector. Keeps the V2-specific
       class names so JS hooks don't change. */
    .report-v2-rail {
      position: sticky;
      top: 84px;
      align-self: start;
      display: flex; flex-direction: column; gap: 6px;
      padding: 14px 10px;
      background: var(--surface-white);
      border: 1px solid rgba(28, 51, 67, 0.1);
      border-radius: 16px;
      box-shadow: 0 5px 14px rgba(29, 56, 45, 0.04);
      font-size: 12px;
      max-height: calc(100vh - 108px);
      overflow: auto;
    }
    .report-v2-rail-title,
    .report-surface-rail-title {
      font-size: 10px; font-weight: 900; letter-spacing: 0.12em;
      text-transform: uppercase; color: var(--ink-muted);
      margin: 0 0 6px 8px;
    }
    .report-v2-rail a {
      display: block;
      padding: 7px 10px;
      border-radius: 8px;
      color: var(--ink-slate);
      text-decoration: none;
      font-weight: 600;
      transition: background 0.15s ease, color 0.15s ease;
    }
    .report-v2-rail a:hover { background: var(--surface-pale-cool); color: var(--ink-navy); }
    .report-v2-rail a.is-active {
      background: var(--surface-pale-cool); color: var(--ink-navy); font-weight: 800;
      box-shadow: inset 3px 0 0 var(--ink-navy);
    }
    .report-v2-rail-sublist {
      display: flex; flex-direction: column; gap: 2px;
      margin: 2px 0 4px 0;
      padding-left: 0;
      border-left: 0;
    }
    .report-v2-rail-sublink {
      padding: 4px 10px 4px 22px !important;
      font-size: 11px;
      font-weight: 500 !important;
      color: var(--ink-muted) !important;
      position: relative;
      /* 2026-05-19 polish — clamp long section headings to 2 lines
         with an ellipsis so a 12-word title doesn't push the rail
         item to 3 lines tall. The full heading is preserved as
         `title=` on the <a> for hover-tooltip + screen readers. */
      display: -webkit-box;
      -webkit-line-clamp: 2;
      -webkit-box-orient: vertical;
      overflow: hidden;
      line-height: 1.35;
      word-break: break-word;
    }
    .report-v2-rail-sublink::before {
      content: ""; position: absolute;
      left: 12px; top: 50%;
      width: 5px; height: 1px;
      background: var(--border-cool);
    }
    .report-v2-rail-sublink:hover { color: var(--ink-navy) !important; }
    .report-v2-rail-sublink.is-active {
      background: var(--surface-pale-cool) !important; color: var(--ink-navy) !important; font-weight: 700 !important;
      box-shadow: inset 3px 0 0 var(--border-cool) !important;
    }
    .report-v2-rail-separator {
      border: 0; height: 1px;
      background: rgba(28, 51, 67, 0.12);
      margin: 8px 4px 6px;
    }
    @media (max-width: 1080px) {
      .report-v2-rail {
        position: sticky; top: 0; z-index: 5;
        flex-direction: row; gap: 4px; overflow-x: auto; max-height: none;
        white-space: nowrap;
        padding: 8px 10px;
        border-radius: 0;
      }
      .report-v2-rail-title { display: none; }
      .report-v2-rail a { padding: 6px 10px; font-size: 11px; }
      .report-v2-rail a.is-active { box-shadow: inset 0 -2px 0 var(--ink-navy); background: transparent; }
      .report-v2-rail-sublist { display: none; }
      .report-v2-rail-separator { display: none; }
    }

    /* ---------- Executive read paragraph spacing ----------
       Visible breathing room between multiple executive paragraphs so
       the prose reads like a real lede, not one wall of text. */
    .report-v2-exec-summary { margin: 0 0 14px 0; }
    .report-v2-exec-summary:last-child { margin-bottom: 0; }

    /* ---------- Analyst Brief: justify the structured sub-blocks ---------- */
    .report-v2-brief-sub-body {
      text-align: justify; text-wrap: pretty; -webkit-hyphens: auto; text-justify: inter-word; hyphens: auto;
    }

    /* ---------- Detailed Analysis: center the prose column ---------- */
    .report-v2-detailed-list {
      margin-left: auto; margin-right: auto;
    }
    .report-v2-detailed-section {
      margin-left: auto; margin-right: auto;
    }

    /* ---------- Detailed Analysis heading row (heading + tiny AI★) ---------- */
    .report-v2-detailed-heading-row {
      display: flex; align-items: center; gap: 8px;
      margin-bottom: 10px;
    }
    .report-v2-detailed-heading-row .report-v2-detailed-heading { margin: 0; }
    .report-v2-detailed-heading-row .ai-star-btn { flex-shrink: 0; }

    /* ---------- Compact embedded transcript recommendations ----------
       Thumb + channel/speaker icons in a narrow LEFT column, title and
       actions on the right. Inspired by the compare-report source grid. */
    .report-v2-detailed-recs-list { grid-template-columns: 1fr; }
    @media (min-width: 980px) {
      .report-v2-detailed-recs-list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    }
    .report-v2-rec-card {
      display: grid; grid-template-columns: 104px minmax(0, 1fr); gap: 10px;
      padding: 8px 10px;
      background: var(--surface-white); border: 1px solid rgba(28, 51, 67, 0.08);
      border-radius: 10px;
      list-style: none;
    }
    .report-v2-rec-left {
      display: flex; flex-direction: column; gap: 4px;
      min-width: 0;
    }
    .report-v2-rec-thumb {
      width: 104px; height: 58px; border-radius: 8px; overflow: hidden;
      background: var(--surface-mint);
    }
    .report-v2-rec-thumb a, .report-v2-rec-thumb img { display: block; width: 100%; height: 100%; }
    .report-v2-rec-thumb img { object-fit: cover; }
    .report-v2-rec-thumb-fallback {
      display: flex; align-items: center; justify-content: center;
      width: 100%; height: 100%;
      color: var(--ink-muted); font-size: 14px; font-weight: 900;
    }
    .report-v2-rec-meta-line {
      display: inline-flex; align-items: center; gap: 4px;
      font-size: 10.5px; font-weight: 600; color: var(--ink-slate);
      max-width: 104px;
      overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    }
    .report-v2-rec-meta-icon { width: 11px; height: 11px; color: var(--ink-slate); flex-shrink: 0; }
    .report-v2-rec-meta-line .entity-page-link-icon { width: 11px; height: 11px; }
    .report-v2-rec-meta-text {
      overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    }
    .report-v2-rec-right { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
    .report-v2-rec-title {
      margin: 0; font-size: 12.5px; font-weight: 800; color: var(--ink-navy);
      line-height: 1.35;
      display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
    }
    .report-v2-rec-title a { color: inherit; text-decoration: none; }
    .report-v2-rec-title a:hover { text-decoration: underline; }
    .report-v2-rec-tags {
      display: flex; flex-wrap: wrap; gap: 4px; align-items: center;
    }
    .report-v2-rec-date {
      font-size: 10.5px; color: var(--ink-muted); font-weight: 600;
    }
    .report-v2-rec-actions {
      display: flex; flex-wrap: wrap; gap: 6px; align-items: center;
      margin-top: 2px;
    }
    .report-v2-rec-action {
      display: inline-flex; align-items: center;
      padding: 3px 9px; border-radius: 999px;
      background: var(--surface-white); border: 1px solid var(--border-cool); color: var(--ink-navy);
      font-size: 9.5px; font-weight: 800; letter-spacing: 0.05em;
      text-transform: uppercase; text-decoration: none;
    }
    .report-v2-rec-action:hover { background: var(--surface-pale-cool); }

    /* ---------- What changed: aligned 3-column grid ----------
       Single grid where rows align across the three categories. Empty
       cells render as invisible spacers so the rhythm holds even when
       one column has fewer items. */
    .report-v2-change-grid {
      display: grid; gap: 10px;
      grid-template-columns: repeat(3, minmax(0, 1fr));
      align-items: stretch;
    }
    @media (max-width: 980px) {
      .report-v2-change-grid { grid-template-columns: 1fr; }
      .report-v2-change-item-empty { display: none; }
    }
    .report-v2-change-col-title {
      margin: 0 0 4px 0;
      font-size: 11px; font-weight: 900; letter-spacing: 0.12em;
      text-transform: uppercase;
    }
    /* "New today" reuses the warm gold accent the #1 Key Driver uses,
       since it carries the same "most important right now" meaning. */
    .report-v2-change-col-new    { color: var(--brand-bronze); }
    .report-v2-change-col-stable { color: var(--ink-navy); }
    /* Faded reads as "winding down" — muted slate, not amber, so the
       warm gold palette stays reserved for the "most important"
       callouts (top Key Driver + New today). */
    .report-v2-change-col-faded  { color: var(--ink-muted); }
    .report-v2-change-item {
      display: flex; flex-direction: column; gap: 6px;
      padding: 10px 12px; border-radius: 10px;
      background: var(--surface-white); border: 1px solid rgba(28, 51, 67, 0.08);
      border-left-width: 3px;
    }
    /* New today carries the same warm gold gradient as the top Key
       Driver card — both mean "most important right now". */
    .report-v2-change-item-new    {
      border-left-color: var(--gold-accent);
      background: linear-gradient(180deg, var(--surface-warm-warning) 0%, var(--surface-cream) 100%);
      border-color: var(--warning-border-soft);
    }
    .report-v2-change-item-stable { border-left-color: var(--ink-navy); }
    /* Quiet slate fill for Faded, so the column reads as "winding down"
       rather than highlighted. Reserves the warm gold for "most
       important" callouts. */
    .report-v2-change-item-faded  { border-left-color: var(--ink-cool-grey); background: var(--surface-pale-cool); }
    .report-v2-change-item-empty {
      border-radius: 10px; background: transparent;
      border: 1px dashed transparent;
    }
    /* One-line title clip with tooltip for the full text. */
    .report-v2-change-item-title {
      margin: 0;
      font-size: 13.5px; font-weight: 800; color: var(--ink-navy); line-height: 1.4;
      white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
      cursor: help;
    }
    .report-v2-change-item-body {
      margin: 0; font-size: 12.5px; line-height: 1.55; color: var(--ink-slate);
    }
    .report-v2-change-item-tags {
      display: flex; flex-wrap: wrap; gap: 4px; margin-top: 2px;
    }
    /* Use the standard topic-chip palette: subtle background, full
       asset-icon support via the macro. Compact sizing so the chip row
       reads as metadata, not a primary action. */
    .topic-chip.report-v2-change-item-tag {
      font-size: 10.5px; padding: 1px 8px;
    }

    /* ---------- Key drivers: top-rank accent + tighter meta row ---------- */
    .report-v2-driver-item-top {
      background: linear-gradient(180deg, var(--surface-warm-warning) 0%, var(--surface-cream) 100%);
      border-color: var(--warning-border-soft);
    }
    .report-v2-driver-item-top .report-v2-driver-rank {
      background: linear-gradient(180deg, var(--gold-accent) 0%, var(--brand-bronze) 100%);
      color: var(--surface-cream);
      box-shadow: 0 2px 6px rgba(163, 124, 26, 0.30);
    }
    .report-v2-driver-meta { gap: 6px; }

    /* ---------- Market & asset implications: paragraph read wraps ---------- */
    .report-v2-implication-read {
      cursor: default;
    }
    .report-v2-implication-pills { align-items: center; }

    /* ---------- Niche assets: stronger LEFT-side color ---------- */
    .report-v2-niche-item-bullish .report-v2-niche-side {
      background: linear-gradient(180deg, var(--surface-mint-deep) 0%, var(--surface-mint-deep) 100%);
    }
    .report-v2-niche-item-bullish .report-v2-niche-ticker,
    .report-v2-niche-item-bullish .report-v2-niche-direction { color: var(--positive-text-deep); }
    .report-v2-niche-item-bearish .report-v2-niche-side {
      background: linear-gradient(180deg, var(--danger-border-soft) 0%, var(--rust-soft) 100%);
    }
    .report-v2-niche-item-bearish .report-v2-niche-ticker,
    .report-v2-niche-item-bearish .report-v2-niche-direction { color: var(--danger-text-deep); }
    .report-v2-niche-item-unclear .report-v2-niche-side {
      background: linear-gradient(180deg, var(--border-pale) 0%, var(--border-pale) 100%);
    }
    .report-v2-niche-item-unclear .report-v2-niche-ticker,
    .report-v2-niche-item-unclear .report-v2-niche-direction { color: var(--ink-slate); }

    /* ---------- Niche assets polish ---------- */
    .report-v2-niche-rationale-row {
      display: flex; align-items: center; justify-content: space-between;
      gap: 12px; margin-top: 2px;
    }
    .report-v2-niche-rationale {
      flex: 0 1 75%; max-width: 75%; min-width: 0;
      margin: 0;
      font-size: 13px; line-height: 1.55; color: var(--ink-navy);
      text-align: justify; text-wrap: pretty; -webkit-hyphens: auto; text-justify: inter-word; hyphens: auto;
      display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
      overflow: hidden;
      cursor: help;
    }
    .report-v2-niche-actions {
      flex: 0 0 auto;
      display: inline-flex; align-items: center; gap: 8px;
    }
    .report-v2-niche-speaker-link {
      display: inline-flex; align-items: center; gap: 4px;
      color: var(--ink-slate); text-decoration: none; font-weight: 600;
    }
    .report-v2-niche-speaker-link:hover { text-decoration: underline; }
    .report-v2-niche-speaker-icon { width: 12px; height: 12px; color: var(--ink-slate); flex-shrink: 0; }
    /* Items beyond the 5th — hidden in Report mode until the user clicks
       "View all". On the Niche tab they're visible by default since the
       hide rule is scoped to data-tab-mode="report". */
    .report-v2-layout[data-tab-mode="report"] .report-v2-niche-list:not(.is-expanded) .report-v2-niche-extra {
      display: none !important;
    }
    .report-v2-niche-toggle-wrap {
      margin-top: 12px;
      display: flex; justify-content: flex-start;
    }
    .report-v2-niche-toggle {
      display: inline-flex; align-items: center;
      padding: 6px 14px; border-radius: 999px;
      background: var(--surface-white); border: 1px solid var(--border-cool); color: var(--ink-navy);
      font-size: 11px; font-weight: 800; letter-spacing: 0.06em;
      text-transform: uppercase; cursor: pointer;
      transition: background 0.15s ease, border-color 0.15s ease;
    }
    .report-v2-niche-toggle:hover { background: var(--surface-pale-cool); border-color: var(--ink-cool-grey-pale); }

    /* ---------- Ongoing questions: justified prose ---------- */
    .report-v2-ongoing-question {
      text-align: justify; text-wrap: pretty; -webkit-hyphens: auto; text-justify: inter-word; hyphens: auto;
    }
    .report-v2-ongoing-update {
      text-align: justify; text-wrap: pretty; -webkit-hyphens: auto; text-justify: inter-word; hyphens: auto;
    }

    /* ---------- Watch next / Ask or track: breathing room ----------
       The asset bubble at the top-right and the AI★ row at the bottom
       were too close together. Add a gap and align AI/Track to flex-end. */
    .report-v2-next-item-actions { gap: 8px; }
    .report-v2-next-item-actions-row { gap: 8px; }

    /* ---------- Track button — "tracked" success state ---------- */
    .report-v2-track-btn.is-tracked {
      background: var(--positive-text-deep); color: var(--surface-cream); border-color: var(--positive-text-deep);
    }
    .report-v2-track-btn.is-tracked::before {
      content: "✓"; margin-right: 5px; background: none;
      -webkit-mask: none; mask: none; width: auto; height: auto;
    }

    /* ---------- View-mode toggle ported from Material report ----------
       Same chrome the Material report uses: 10px-radius soft tray with
       active pill in dark navy + leading dot indicator. Keeps V2 class
       names so the existing JS handler stays intact. */
    .report-v2-view-toggle {
      display: flex; gap: 4px;
      padding: 4px;
      margin: 0 4px 10px 4px;
      border-radius: 10px;
      background: var(--surface-pale-cool);
      border: 1px solid rgba(28, 51, 67, 0.1);
      overflow: visible;
    }
    .report-v2-view-toggle-btn {
      flex: 1 1 auto;
      display: inline-flex; align-items: center; justify-content: center; gap: 5px;
      padding: 6px 10px;
      border-radius: 7px;
      background: transparent; border: 1px solid transparent;
      cursor: pointer;
      font-size: 11px; font-weight: 800; letter-spacing: 0.08em;
      text-transform: uppercase; color: var(--ink-muted);
      transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
    }
    .report-v2-view-toggle-btn::before {
      content: ""; display: inline-block;
      width: 6px; height: 6px; border-radius: 999px;
      background: transparent; border: 1px solid var(--border-pale);
      transition: background 0.15s ease, border-color 0.15s ease;
    }
    .report-v2-view-toggle-btn:hover:not([aria-pressed="true"]) {
      color: var(--ink-navy);
      background: rgba(255, 255, 255, 0.5);
    }
    .report-v2-view-toggle-btn[aria-pressed="true"] {
      background: var(--ink-navy);
      color: var(--surface-cream);
      border-color: var(--ink-navy);
      box-shadow: 0 2px 6px rgba(28, 51, 67, 0.25);
    }
    .report-v2-view-toggle-btn[aria-pressed="true"]::before {
      background: var(--surface-cream);
      border-color: var(--surface-cream);
    }
    .report-v2-view-toggle-label {
      font-size: 10px; font-weight: 900; letter-spacing: 0.12em;
      text-transform: uppercase; color: var(--ink-muted);
      margin: 0 0 4px 8px;
    }

    /* ---------- Best-transcript cards: corner-AI + clickable + relevance lead ---------- */
    .report-v2-rec-card {
      position: relative;
      display: grid; grid-template-columns: 104px minmax(0, 1fr); gap: 12px;
      padding: 10px 12px;
      padding-right: 40px;   /* room for the corner AI★ */
      background: var(--surface-white); border: 1px solid rgba(28, 51, 67, 0.08);
      border-radius: 10px;
      list-style: none;
      transition: border-color 0.16s ease, box-shadow 0.16s ease, transform 0.16s ease;
    }
    .report-v2-rec-card-clickable { cursor: pointer; }
    .report-v2-rec-card-clickable:hover,
    .report-v2-rec-card-clickable:focus-visible {
      border-color: rgba(28, 51, 67, 0.18);
      box-shadow: 0 10px 22px rgba(28, 51, 67, 0.08);
      transform: translateY(-1px);
      outline: none;
    }
    .report-v2-rec-corner-ai {
      position: absolute; bottom: 6px; right: 6px; z-index: 2;
    }
    .report-v2-rec-thumb {
      width: 104px; height: 58px; border-radius: 8px; overflow: hidden;
      background: var(--surface-mint);
    }
    .report-v2-rec-thumb img { display: block; width: 100%; height: 100%; object-fit: cover; }
    .report-v2-rec-thumb-fallback {
      display: flex; align-items: center; justify-content: center;
      width: 100%; height: 100%;
      color: var(--ink-muted); font-size: 14px; font-weight: 900;
    }
    .report-v2-rec-body { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
    /* Date in top-right meta slot — same muted weight-600 style used
       elsewhere on the page (e.g. report-v2-related-meta). */
    .report-v2-rec-date {
      position: absolute; top: 10px; right: 12px;
      font-size: 11.5px; color: var(--ink-slate); font-weight: 600;
    }
    .report-v2-rec-relevance {
      align-self: flex-start;
      font-size: 9.5px;
      margin-bottom: 2px;
    }
    .report-v2-rec-title {
      margin: 0; font-size: 13px; font-weight: 800; color: var(--ink-navy);
      line-height: 1.35;
      display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
    }
    /* Best-transcript meta sits BELOW the thumbnail in the left column,
       with channel and speaker stacked tight on their own lines —
       smaller and more muted than the title so the title remains the
       visual anchor on the right side. */
    .report-v2-rec-left {
      display: flex; flex-direction: column; gap: 4px;
      width: 104px; min-width: 0;
    }
    .report-v2-rec-meta {
      display: flex; flex-direction: column; gap: 1px;
      width: 104px;
      font-size: 10px; color: var(--ink-cool-grey); font-weight: 500;
      line-height: 1.25;
    }
    .report-v2-rec-meta-line {
      display: inline-flex; align-items: center; gap: 3px;
      max-width: 104px;
      overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
      min-width: 0;
      font-size: 10px; font-weight: 500; color: var(--ink-cool-grey);
    }
    .report-v2-rec-meta-line .entity-page-link-icon {
      width: 9px; height: 9px; opacity: 0.7; flex-shrink: 0;
    }
    .report-v2-rec-meta-line .report-v2-rec-meta-icon {
      width: 9px; height: 9px; color: var(--ink-cool-grey); flex-shrink: 0;
    }
    .report-v2-rec-meta-line .report-v2-rec-meta-text {
      color: var(--ink-cool-grey);
      overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
      min-width: 0;
    }

    /* ---------- Market & asset implications: labeled rows under the chip row ---------- */
    /* Pills sit on a single line and clip at the card edge — only
       stance/horizon/confidence chips live here; the row gets a title
       attribute combining the three so a hover still surfaces the
       clipped values. Confirms/invalidates/workspace are their own
       paragraph lines below. */
    .report-v2-implication-pills {
      /* Was `nowrap` + overflow:hidden, which clipped pill labels
         mid-word ("HORIZON: MEDIUM T", "CONFIDENCE: HIG") on narrow
         cards. Wrap to a second row instead so the labels stay
         readable. On wide cards nothing changes — the three pills
         still fit on one line. The `title` attribute on the parent
         and on each chip still provides the hover summary. */
      flex-wrap: wrap;
      min-width: 0;
    }
    .report-v2-implication-pills > .report-v2-chip {
      flex: 0 0 auto;
      min-width: 0;
      white-space: nowrap;
    }
    .report-v2-implication-line {
      margin: 4px 0 0 0;
      font-size: 12.5px; line-height: 1.55; color: var(--ink-slate);
    }
    .report-v2-implication-line:first-of-type { margin-top: 6px; }
    .report-v2-implication-kicker {
      display: inline-block;
      font-size: 10px; font-weight: 900; letter-spacing: 0.06em;
      text-transform: uppercase; color: var(--ink-navy);
      margin-right: 6px;
    }
    .report-v2-implication-kicker-good { color: var(--positive-text-deep); }
    .report-v2-implication-kicker-bad  { color: var(--danger-text-deep); }

    /* ---------- Niche assets: stronger color difference ---------- */
    .report-v2-niche-item-bullish .report-v2-niche-side {
      background: linear-gradient(180deg, var(--positive-bg-bright) 0%, var(--positive-border-dark) 100%);
    }
    .report-v2-niche-item-bullish .report-v2-niche-ticker,
    .report-v2-niche-item-bullish .report-v2-niche-direction { color: var(--surface-cream); }
    .report-v2-niche-item-bullish { border-left: 3px solid var(--positive-border-dark); }
    .report-v2-niche-item-bearish .report-v2-niche-side {
      background: linear-gradient(180deg, var(--rust-bright) 0%, var(--danger-bg-bright) 100%);
    }
    .report-v2-niche-item-bearish .report-v2-niche-ticker,
    .report-v2-niche-item-bearish .report-v2-niche-direction { color: var(--surface-cream); }
    .report-v2-niche-item-bearish { border-left: 3px solid var(--danger-bg-bright); }
    .report-v2-niche-item-unclear .report-v2-niche-side {
      background: linear-gradient(180deg, var(--ink-cool-grey) 0%, var(--ink-muted) 100%);
    }
    .report-v2-niche-item-unclear .report-v2-niche-ticker,
    .report-v2-niche-item-unclear .report-v2-niche-direction { color: var(--surface-white); }
    .report-v2-niche-item-unclear { border-left: 3px solid var(--ink-muted); }

    /* ============================================================
       Length × Mode disclosure matrix.

       Two axes:
         - data-length-mode = short | medium | long | detailed
         - data-view-mode   = compact | full

       Eight cell keys (sc/sf/mc/mf/lc/lf/dc/df). Each section
       carries data-show-in="<keys>" listing the cells it should
       appear in. Eight CSS rules below hide any section that doesn't
       include the active cell.

       Compact mode never deletes data — sections with the right key
       still show, just less of them (count caps below). Sections
       outside the active cell remain in the DOM, just hidden, so
       deep-links keep working.
    ============================================================ */
    .report-v2-layout[data-length-mode="short"][data-view-mode="compact"]    [data-show-in]:not([data-show-in~="sc"]) { display: none !important; }
    .report-v2-layout[data-length-mode="short"][data-view-mode="full"]       [data-show-in]:not([data-show-in~="sf"]) { display: none !important; }
    .report-v2-layout[data-length-mode="medium"][data-view-mode="compact"]   [data-show-in]:not([data-show-in~="mc"]) { display: none !important; }
    .report-v2-layout[data-length-mode="medium"][data-view-mode="full"]      [data-show-in]:not([data-show-in~="mf"]) { display: none !important; }
    .report-v2-layout[data-length-mode="long"][data-view-mode="compact"]     [data-show-in]:not([data-show-in~="lc"]) { display: none !important; }
    .report-v2-layout[data-length-mode="long"][data-view-mode="full"]        [data-show-in]:not([data-show-in~="lf"]) { display: none !important; }
    .report-v2-layout[data-length-mode="detailed"][data-view-mode="compact"] [data-show-in]:not([data-show-in~="dc"]) { display: none !important; }
    .report-v2-layout[data-length-mode="detailed"][data-view-mode="full"]    [data-show-in]:not([data-show-in~="df"]) { display: none !important; }

    /* ============================================================
       Per-section count caps. Each list carries its natural full set
       of items; the caps below trim what's visible per cell.

       Caps follow the spec:
         Key drivers       sc 2,  sf 3,  mc 3,  lc 5,  dc 5
         Market impl.      sf 3,  lc 4,  dc 4
         Related transcripts  sf 2, mc 2, mf 3, lc 3, lf 3, dc 3, df 3
         Watch/Ask         sc 1,  sf 3,  mc 3,  lc 5
         Niche assets      lf/df preview already enforced via
                           .report-v2-niche-extra
    ============================================================ */
    /* Key drivers caps */
    .report-v2-layout[data-length-mode="short"][data-view-mode="compact"]  .report-v2-driver-list > li:nth-child(n+3) { display: none !important; }
    .report-v2-layout[data-length-mode="short"][data-view-mode="full"]     .report-v2-driver-list > li:nth-child(n+4) { display: none !important; }
    .report-v2-layout[data-length-mode="medium"][data-view-mode="compact"] .report-v2-driver-list > li:nth-child(n+4) { display: none !important; }
    .report-v2-layout[data-length-mode="long"][data-view-mode="compact"]   .report-v2-driver-list > li:nth-child(n+6) { display: none !important; }
    .report-v2-layout[data-length-mode="detailed"][data-view-mode="compact"] .report-v2-driver-list > li:nth-child(n+6) { display: none !important; }
    /* Market implications caps */
    .report-v2-layout[data-length-mode="short"][data-view-mode="full"]     .report-v2-implications-grid > * :nth-child(n+4),
    .report-v2-layout[data-length-mode="short"][data-view-mode="full"]     .report-v2-implications-grid > article:nth-child(n+4) { display: none !important; }
    .report-v2-layout[data-length-mode="long"][data-view-mode="compact"]   .report-v2-implications-grid > article:nth-child(n+5) { display: none !important; }
    .report-v2-layout[data-length-mode="detailed"][data-view-mode="compact"] .report-v2-implications-grid > article:nth-child(n+5) { display: none !important; }
    /* Related transcripts caps */
    .report-v2-layout[data-length-mode="short"][data-view-mode="full"]     .report-v2-related-list > li:nth-child(n+3) { display: none !important; }
    .report-v2-layout[data-length-mode="medium"][data-view-mode="compact"] .report-v2-related-list > li:nth-child(n+3) { display: none !important; }
    .report-v2-layout[data-length-mode="medium"][data-view-mode="full"]    .report-v2-related-list > li:nth-child(n+4) { display: none !important; }
    .report-v2-layout[data-length-mode="long"][data-view-mode="compact"]   .report-v2-related-list > li:nth-child(n+4) { display: none !important; }
    .report-v2-layout[data-length-mode="long"][data-view-mode="full"]      .report-v2-related-list > li:nth-child(n+4) { display: none !important; }
    .report-v2-layout[data-length-mode="detailed"][data-view-mode="compact"] .report-v2-related-list > li:nth-child(n+4) { display: none !important; }
    .report-v2-layout[data-length-mode="detailed"][data-view-mode="full"]  .report-v2-related-list > li:nth-child(n+4) { display: none !important; }
    /* Watch next + Ask or Track caps (per column) */
    .report-v2-layout[data-length-mode="short"][data-view-mode="compact"]  .report-v2-next-list > li:nth-child(n+2) { display: none !important; }
    .report-v2-layout[data-length-mode="short"][data-view-mode="full"]     .report-v2-next-list > li:nth-child(n+4) { display: none !important; }
    .report-v2-layout[data-length-mode="medium"][data-view-mode="compact"] .report-v2-next-list > li:nth-child(n+4) { display: none !important; }
    .report-v2-layout[data-length-mode="long"][data-view-mode="compact"]   .report-v2-next-list > li:nth-child(n+6) { display: none !important; }
    .report-v2-layout[data-length-mode="detailed"][data-view-mode="compact"] .report-v2-next-list > li:nth-child(n+6) { display: none !important; }
    /* Tracked questions update cap */
    .report-v2-layout[data-length-mode="medium"][data-view-mode="compact"] .report-v2-tracked-list > li:nth-child(n+2) { display: none !important; }
    .report-v2-layout[data-length-mode="long"][data-view-mode="compact"]   .report-v2-tracked-list > li:nth-child(n+4) { display: none !important; }
    .report-v2-layout[data-length-mode="detailed"][data-view-mode="compact"] .report-v2-tracked-list > li:nth-child(n+4) { display: none !important; }

    /* ============================================================
       Compact-mode CTA strip — only renders when the layout is in
       compact view. Sits between hero and the rest, mirroring the
       hero card width but with a quieter inset look so it reads
       as "navigation back to the full view", not as content.
    ============================================================ */
    .report-v2-compact-cta {
      display: none;
      margin: 0 0 16px 0;
      padding: 14px 20px;
      border: 1px dashed rgba(180, 175, 165, 0.55);
      border-radius: 14px;
      background: rgba(255, 251, 240, 0.55);
      gap: 14px;
      align-items: center;
      flex-wrap: wrap;
      justify-content: space-between;
    }
    .report-v2-layout[data-view-mode="compact"] .report-v2-compact-cta {
      display: flex;
    }
    .report-v2-compact-cta-text {
      flex: 1 1 240px;
      color: var(--brand-bronze);
      font-size: 13px;
      line-height: 1.45;
    }
    .report-v2-compact-cta-text strong {
      color: var(--bronze-deep);
      font-weight: 600;
    }
    .report-v2-compact-cta-actions {
      display: flex;
      gap: 8px;
      flex-wrap: wrap;
    }
    .report-v2-compact-cta-btn {
      appearance: none;
      border: 1px solid rgba(120, 110, 95, 0.35);
      background: var(--surface-warm-warning);
      color: var(--bronze-deep);
      padding: 7px 14px;
      border-radius: 999px;
      font-size: 13px;
      font-weight: 500;
      cursor: pointer;
      transition: background 120ms ease, border-color 120ms ease, transform 120ms ease;
    }
    .report-v2-compact-cta-btn:hover {
      background: var(--surface-white);
      border-color: rgba(80, 70, 55, 0.55);
      transform: translateY(-1px);
    }
    .report-v2-compact-cta-btn.is-primary {
      background: var(--bronze-deep);
      color: var(--surface-warm-warning);
      border-color: var(--bronze-deep);
    }
    .report-v2-compact-cta-btn.is-primary:hover {
      background: var(--ink-darkest);
      border-color: var(--ink-darkest);
    }

    /* ============================================================
       Rail: split into a pinned top (View mode toggle) and a
       scrollable body so the toggle is always visible even when
       the section list overflows. The rail caps at viewport height
       (minus the sticky top offset) so the inner scroll engages.
    ============================================================ */
    .report-v2-rail {
      /* Topbar (fixed) ends around y=112 once the report-shell extension
         is suppressed; offset the sticky rail to sit safely below it so
         the View Mode toggle at the top of the rail is never tucked
         behind the topbar when the page scrolls. */
      top: 124px;
      overflow: hidden;
      max-height: calc(100vh - 140px);
    }
    .report-v2-rail-fixed {
      flex: 0 0 auto;
      padding-bottom: 6px;
      border-bottom: 1px solid rgba(28, 51, 67, 0.08);
      margin-bottom: 6px;
    }
    .report-v2-rail-scroll {
      flex: 1 1 auto;
      min-height: 0;
      overflow-y: auto;
      overflow-x: hidden;
      display: flex;
      flex-direction: column;
      gap: 6px;
      padding-right: 4px;
    }
    .report-v2-rail-scroll::-webkit-scrollbar { width: 6px; }
    .report-v2-rail-scroll::-webkit-scrollbar-thumb {
      background: rgba(28, 51, 67, 0.18); border-radius: 999px;
    }

    /* ============================================================
       Niche cards: trim height — tighter padding, smaller gaps,
       1-line clamp on the rationale, compact speaker/channel row.
       The speakers row uses align-items: center so the kicker,
       icons, and text sit on the same visual axis.
    ============================================================ */
    .report-v2-niche-item {
      min-height: 0;
    }
    .report-v2-niche-body {
      padding: 6px 12px !important;
      gap: 3px !important;
    }
    .report-v2-niche-name { font-size: 13.5px; line-height: 1.25; }
    .report-v2-niche-head { gap: 6px; row-gap: 3px; }
    .report-v2-niche-rationale {
      display: -webkit-box;
      -webkit-line-clamp: 1;
      -webkit-box-orient: vertical;
      overflow: hidden;
      font-size: 12.5px;
      line-height: 1.4;
    }
    .report-v2-niche-side { padding: 6px 10px; }
    .report-v2-niche-ticker { font-size: 15px; }
    .report-v2-niche-direction { font-size: 9.5px; }
    /* Speakers / channels row: line up the kicker ("Mentioned by:" or
       "Seen in:") with each speaker/channel pill on the same vertical
       midline. Was align-items: baseline which left the SVG icons
       sitting visibly higher than the kicker text. */
    .report-v2-niche-speakers {
      align-items: center;
      row-gap: 2px;
      line-height: 1.2;
    }
    .report-v2-niche-speaker-link {
      align-items: center;
      line-height: 1.2;
    }
    .report-v2-niche-speaker-icon {
      vertical-align: middle;
    }

    /* ============================================================
       Source summary — 2-column layouts:
         - "Most influential sources" cards arrange in 2 columns
         - Source package transcript cards arrange in 2 columns
       Both collapse to a single column on narrow viewports.
    ============================================================ */
    .report-v2-source-list {
      display: grid;
      grid-template-columns: repeat(2, minmax(0, 1fr));
      gap: 8px;
    }
    .report-v2-source-package {
      display: grid;
      grid-template-columns: repeat(2, minmax(0, 1fr));
      gap: 10px;
    }
    @media (max-width: 900px) {
      .report-v2-source-list { grid-template-columns: 1fr; }
      .report-v2-source-package { grid-template-columns: 1fr; }
    }

    /* "View all sources" entry button — left-aligned, opens the
       focused sources-only view in a new tab. Hidden on that focused
       view itself (the source package is already the main content). */
    .report-v2-source-view-all-wrap {
      display: flex;
      justify-content: flex-start;
      margin: 12px 0 6px 0;
    }
    .report-v2-source-view-all-btn {
      display: inline-flex; align-items: center;
      padding: 6px 14px; border-radius: 999px;
      background: var(--ink-navy); color: var(--surface-cream);
      font-size: 11px; font-weight: 800; letter-spacing: 0.06em;
      text-transform: uppercase; text-decoration: none;
      border: 1px solid var(--ink-navy);
      transition: background 0.15s ease, color 0.15s ease;
    }
    .report-v2-source-view-all-btn:hover {
      background: var(--surface-white); color: var(--ink-navy);
    }
    /* Source package details visibility is now driven by the tab system
       alone: data-tab-include="sources" on the <details> element means
       it shows on the Sources tab and hides on Report/Niche/Executive.
       The "View all sources" button uses data-tab-jump="sources" to
       switch the tab in-place — no separate focus mode is needed. */
    /* Focused view (?focus=sources): strip the page down to the hero
       and the Source summary section so the user sees only sources.
       Hide the now-redundant "View all sources" button. */
    .report-v2-layout[data-focus-mode="sources"] .report-v2-shell > .report-v2-card:not(#rv2-hero):not(#rv2-sources) {
      display: none !important;
    }
    .report-v2-layout[data-focus-mode="sources"] .report-v2-shell > .report-v2-compact-cta {
      display: none !important;
    }
    .report-v2-layout[data-focus-mode="sources"] .report-v2-source-view-all-wrap {
      display: none;
    }

    /* Idea-score chip: give it a help-cursor so the hover tooltip
       is obviously interactive. */
    .report-v2-niche-head .report-v2-chip[title] {
      cursor: help;
    }

    /* ============================================================
       AI-star reveal policy for report detail surfaces.
       Hide the AI star by default in the requested sections and
       reveal it only when the owning card / row is hovered or
       receives keyboard focus. Detailed Analysis uses section-level
       hover so the title AI button remains clickable.
       ============================================================ */
    #rv2-drivers .report-v2-driver-actions .ai-star-btn,
    #rv2-implications .report-v2-implication-ai .ai-star-btn,
    #rv2-followups .report-v2-followup-corner-ai .ai-star-btn,
    #rv2-next .report-v2-next-item-actions-row .ai-star-btn,
    #rv2-tracked .report-v2-tracked-actions .ai-star-btn,
    #rv2-sources .report-v2-source-package-ai-corner .ai-star-btn,
    #rv2-detailed .report-v2-detailed-heading-row .ai-star-btn,
    #rv2-detailed .report-v2-rec-corner-ai .ai-star-btn {
      opacity: 0;
      pointer-events: none;
      transform: translateY(2px) scale(0.96);
      transition: opacity 0.16s ease, transform 0.16s ease;
    }

    #rv2-drivers .report-v2-driver-item:hover .report-v2-driver-actions .ai-star-btn,
    #rv2-drivers .report-v2-driver-item:focus-within .report-v2-driver-actions .ai-star-btn,
    #rv2-implications .report-v2-implication-card:hover .report-v2-implication-ai .ai-star-btn,
    #rv2-implications .report-v2-implication-card:focus-within .report-v2-implication-ai .ai-star-btn,
    #rv2-followups .report-v2-followup-card:hover .report-v2-followup-corner-ai .ai-star-btn,
    #rv2-followups .report-v2-followup-card:focus-within .report-v2-followup-corner-ai .ai-star-btn,
    #rv2-next .report-v2-next-item:hover .report-v2-next-item-actions-row .ai-star-btn,
    #rv2-next .report-v2-next-item:focus-within .report-v2-next-item-actions-row .ai-star-btn,
    #rv2-tracked .report-v2-tracked-item:hover .report-v2-tracked-actions .ai-star-btn,
    #rv2-tracked .report-v2-tracked-item:focus-within .report-v2-tracked-actions .ai-star-btn,
    #rv2-sources .report-v2-source-package-item:hover .report-v2-source-package-ai-corner .ai-star-btn,
    #rv2-sources .report-v2-source-package-item:focus-within .report-v2-source-package-ai-corner .ai-star-btn,
    #rv2-detailed .report-v2-detailed-section:hover .report-v2-detailed-heading-row .ai-star-btn,
    #rv2-detailed .report-v2-detailed-section:focus-within .report-v2-detailed-heading-row .ai-star-btn,
    #rv2-detailed .report-v2-rec-card:hover .report-v2-rec-corner-ai .ai-star-btn,
    #rv2-detailed .report-v2-rec-card:focus-within .report-v2-rec-corner-ai .ai-star-btn {
      opacity: 1;
      pointer-events: auto;
      transform: none;
    }

    #rv2-implications .report-v2-implication-ai {
      display: none !important;
      align-items: center;
      justify-content: flex-end;
      min-width: 32px;
      margin-left: auto;
    }

    #rv2-implications .report-v2-implication-card:hover .report-v2-implication-ai,
    #rv2-implications .report-v2-implication-card:focus-within .report-v2-implication-ai {
      display: inline-flex !important;
    }

    /* ============================================================
       Ongoing questions: justify the body text so paragraphs line
       up cleanly with the card edge (matches the way the analyst
       brief and detailed analysis already render).
    ============================================================ */
    .report-v2-ongoing-question,
    .report-v2-ongoing-update {
      text-align: justify; text-wrap: pretty; -webkit-hyphens: auto;
      hyphens: auto;
    }

    /* ============================================================
       Per-scenario count caps for sections newly added to cells by
       the canonical-order pass. Caps follow the spec's "max N" rules:
         - Niche preview in lc/dc: max 3 ⇒ hide nth-child(n+4)
           (df keeps the existing 5-then-View-more behavior)
         - Market & asset implications in mc: top 3
         - Market & asset implications in dc: top 4 (overrides earlier 5 cap)
       Implementation: target the same selectors used by the existing
       matrix block so specificity remains identical.
    ============================================================ */
    /* Niche preview caps for new compact cells */
    .report-v2-layout[data-length-mode="long"][data-view-mode="compact"]     .report-v2-niche-list > li:nth-child(n+4) { display: none !important; }
    .report-v2-layout[data-length-mode="detailed"][data-view-mode="compact"] .report-v2-niche-list > li:nth-child(n+4) { display: none !important; }
    /* Market & asset implications: mc (top 3) — uses the cards inside the grid */
    .report-v2-layout[data-length-mode="medium"][data-view-mode="compact"]   .report-v2-implications-grid > article:nth-child(n+4) { display: none !important; }

    /* ============================================================
       Daily Theme Matrix
       ----------------------------------------------------------------
       Themes (rows) × influential sources (columns). Cells are small
       colored dots that carry the relationship; tooltips on hover
       carry the short reason. Compact mode caps to top 3 × top 3 via
       nth-child rules below. Full mode shows up to 5 × 5.
    ============================================================ */
    .report-v2-tm-scroll {
      overflow-x: auto;
      margin: 0 -4px;
      padding: 0 4px;
    }
    .report-v2-tm {
      width: 100%;
      border-collapse: separate;
      border-spacing: 0;
      font-size: 12.5px;
      table-layout: fixed;
    }
    .report-v2-tm-corner {
      width: 30%;
      min-width: 160px;
      text-align: left;
      font-weight: 800;
      font-size: 10px;
      letter-spacing: 0.08em;
      text-transform: uppercase;
      color: var(--ink-muted);
      padding: 6px 10px 8px 0;
      border-bottom: 1px solid rgba(28, 51, 67, 0.10);
    }
    .report-v2-tm-source {
      padding: 6px 4px 8px 4px;
      border-bottom: 1px solid rgba(28, 51, 67, 0.10);
      font-weight: 700;
      color: var(--ink-slate);
      font-size: 11.5px;
      vertical-align: bottom;
      cursor: help;
    }
    .report-v2-tm-source-label {
      display: inline-block;
      max-width: 100%;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
      vertical-align: middle;
    }
    /* 2026-05-22 — On wide viewports, give the source-column header a
       larger min-width so the truncation server-side (14 chars max
       in daily_v2_context_helpers) doesn't kick in for typical
       channel names. Users still get the title-attribute tooltip on
       hover, but the visible text now fits more often without
       needing the hover. The 14-char server-side truncation in
       `daily_v2_context_helpers.py:220` is the upstream limit;
       widening the column lets the full short label render. */
    @media (min-width: 1100px) {
      .report-v2-tm-source { min-width: 110px; }
      .report-v2-tm-source-label { font-size: 12px; }
    }
    @media (min-width: 1400px) {
      .report-v2-tm-source { min-width: 130px; }
    }
    .report-v2-tm-theme {
      text-align: left;
      padding: 8px 12px 8px 0;
      font-weight: 700;
      color: var(--ink-navy);
      font-size: 13px;
      vertical-align: middle;
      border-bottom: 1px solid rgba(28, 51, 67, 0.06);
      cursor: help;
      width: 30%;
      /* Clip the theme cell to one line; the full theme name is
         exposed via title= so it shows on hover. Without these
         the cell could grow tall enough to wrap onto a 2nd line
         on narrow viewports. */
      overflow: hidden;
      white-space: nowrap;
    }
    .report-v2-tm tbody tr:last-child .report-v2-tm-theme,
    .report-v2-tm tbody tr:last-child .report-v2-tm-cell {
      border-bottom: 0;
    }
    .report-v2-tm-theme-icon {
      display: inline-flex;
      align-items: center;
      width: 18px;
      height: 18px;
      margin-right: 8px;
      vertical-align: middle;
    }
    .report-v2-tm-theme-icon svg,
    .report-v2-tm-theme-icon img {
      width: 18px;
      height: 18px;
    }
    .report-v2-tm-theme-label {
      vertical-align: middle;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
      display: inline-block;
      max-width: calc(100% - 28px);
    }
    .report-v2-tm-cell {
      text-align: center;
      padding: 8px 4px;
      border-bottom: 1px solid rgba(28, 51, 67, 0.06);
      cursor: help;
      transition: background-color 120ms ease;
    }
    .report-v2-tm-cell:hover {
      background-color: rgba(28, 51, 67, 0.04);
    }
    .report-v2-tm-cell-empty:hover {
      background-color: transparent;
    }
    .report-v2-tm-dot {
      display: inline-block;
      width: 12px;
      height: 12px;
      border-radius: 999px;
      vertical-align: middle;
      background: var(--border-cool);
      box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.05);
      transition: width 0.15s ease, height 0.15s ease;
      transform-origin: 50% 50%;
      will-change: transform;
    }
    /* Synchronized pulse — every covered dot (cell and recap) shares the
       same 2.4s keyframe so they grow by the same +15% at the same time.
       Empty / not-covered cells stay still so they read as absence.
       Animation starts from page load → no `animation-delay`, so dots
       stay phase-locked across the whole matrix. */
    @keyframes report-v2-tm-dot-pulse {
      0%, 100% { transform: scale(1); }
      50%      { transform: scale(1.18); }
    }
    .report-v2-tm-cell:not(.report-v2-tm-cell-empty) .report-v2-tm-dot {
      animation: report-v2-tm-dot-pulse 2.4s ease-in-out infinite;
    }
    @media (prefers-reduced-motion: reduce) {
      .report-v2-tm-cell .report-v2-tm-dot { animation: none; }
    }
    /* Cell dot size scales with signal strength. Stronger tones render
       a bigger dot so the matrix is readable at a glance — accent is
       the largest, empty is smallest. Colors picked for clear hue
       separation so the six tones are distinguishable at a glance
       (violet / green / red / sky / amber / slate). */
    .report-v2-tm-cell-accent   .report-v2-tm-dot { background: var(--accent-purple-bright); box-shadow: 0 0 0 3px rgba(124, 58, 237, 0.25); width: 17px; height: 17px; }
    .report-v2-tm-cell-positive .report-v2-tm-dot { background: var(--positive-bg-bright); box-shadow: 0 0 0 1px rgba(22, 163, 74, 0.30); width: 14px; height: 14px; }
    .report-v2-tm-cell-negative .report-v2-tm-dot { background: var(--rust-bright); box-shadow: 0 0 0 1px rgba(220, 38, 38, 0.30); width: 14px; height: 14px; }
    .report-v2-tm-cell-info     .report-v2-tm-dot { background: var(--info-steel-bright); box-shadow: 0 0 0 1px rgba(2, 132, 199, 0.30); width: 12px; height: 12px; }
    .report-v2-tm-cell-caution  .report-v2-tm-dot { background: var(--gold-accent); box-shadow: 0 0 0 1px rgba(249, 115, 22, 0.35); width: 12px; height: 12px; }
    .report-v2-tm-cell-neutral  .report-v2-tm-dot { background: var(--gold-pure); box-shadow: 0 0 0 1px rgba(202, 138, 4, 0.35); width: 9px; height: 9px; }
    .report-v2-tm-cell-empty    .report-v2-tm-dot {
      background: transparent;
      box-shadow: inset 0 0 0 1px rgba(28, 51, 67, 0.10);
      width: 7px; height: 7px;
    }

    /* Recap column at the right edge of the matrix — visual separator
       to mark it as the aggregated summary, plus per-strength dot
       sizing (0 = no coverage, 4 = strongest coverage). Color comes
       from the recap tone class above. */
    .report-v2-tm-cell-recap,
    .report-v2-tm-recap-head {
      border-left: 2px solid rgba(28, 51, 67, 0.18);
      background: rgba(28, 51, 67, 0.03);
    }
    .report-v2-tm-recap-dot { box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.04); }
    .report-v2-tm-recap-dot-0 { width: 6px; height: 6px; }
    .report-v2-tm-recap-dot-1 { width: 9px; height: 9px; }
    .report-v2-tm-recap-dot-2 { width: 12px; height: 12px; }
    .report-v2-tm-recap-dot-3 { width: 15px; height: 15px; }
    .report-v2-tm-recap-dot-4 { width: 18px; height: 18px; }
    /* The strong-signal box-shadow halo would crowd the recap column;
       drop it back to a plain dot but keep the accent color. */
    .report-v2-tm-cell-recap.report-v2-tm-cell-accent .report-v2-tm-dot {
      box-shadow: 0 0 0 1px rgba(124, 58, 237, 0.32);
    }
    /* Same color scheme for the legend strip — kept in sync with the
       matrix cell colors above. */
    .report-v2-tm-dot-accent   { background: var(--accent-purple-bright); box-shadow: 0 0 0 3px rgba(124, 58, 237, 0.25); }
    .report-v2-tm-dot-positive { background: var(--positive-bg-bright); }
    .report-v2-tm-dot-negative { background: var(--rust-bright); }
    .report-v2-tm-dot-info     { background: var(--info-steel-bright); }
    .report-v2-tm-dot-caution  { background: var(--gold-accent); }
    .report-v2-tm-dot-neutral  { background: var(--gold-pure); }
    .report-v2-tm-dot-empty    { background: transparent; box-shadow: inset 0 0 0 1px rgba(28, 51, 67, 0.10); }
    .report-v2-tm-legend {
      list-style: none;
      padding: 0;
      margin: 12px 0 0 0;
      display: flex;
      flex-wrap: wrap;
      gap: 4px 14px;
      font-size: 11px;
      color: var(--ink-muted);
    }
    .report-v2-tm-legend li {
      display: inline-flex;
      align-items: center;
      gap: 6px;
    }
    .report-v2-tm-legend .report-v2-tm-dot {
      width: 9px;
      height: 9px;
    }
    /* Compact preview strip — same visual rhythm as the page-level
       compact CTA, scoped to the matrix card. */
    .report-v2-tm-preview-strip {
      display: none;
      align-items: center;
      justify-content: space-between;
      gap: 12px;
      flex-wrap: wrap;
      padding: 8px 12px;
      margin: 0 0 10px 0;
      border: 1px dashed rgba(28, 51, 67, 0.18);
      border-radius: 8px;
      background: rgba(255, 251, 240, 0.55);
      color: var(--brand-bronze);
      font-size: 12px;
    }
    .report-v2-layout[data-view-mode="compact"] .report-v2-tm-preview-strip {
      display: flex;
    }
    .report-v2-tm-expand {
      appearance: none;
      border: 1px solid rgba(28, 51, 67, 0.25);
      background: var(--surface-white);
      color: var(--ink-navy);
      font-size: 11.5px;
      font-weight: 700;
      padding: 4px 10px;
      border-radius: 999px;
      cursor: pointer;
    }
    .report-v2-tm-expand:hover {
      background: var(--ink-navy);
      color: var(--surface-cream);
      border-color: var(--ink-navy);
    }
    /* Compact-mode caps: top 3 themes × top 3 sources. Column 5 = the
       4th source column (corner counts as 1). Same offset on each row's
       cells (no corner ⇒ source cell at index 4). */
    .report-v2-layout[data-view-mode="compact"] .report-v2-tm thead tr > th:nth-child(n+5),
    .report-v2-layout[data-view-mode="compact"] .report-v2-tm tbody tr > .report-v2-tm-cell:nth-child(n+5) {
      display: none !important;
    }
    .report-v2-layout[data-view-mode="compact"] .report-v2-tm tbody tr:nth-child(n+4) {
      display: none !important;
    }
    /* sr-only — only used by the matrix today, but harmless globally. */
    .sr-only {
      position: absolute;
      width: 1px; height: 1px;
      padding: 0; margin: -1px; overflow: hidden;
      clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
    }

    /* ============================================================
       Most influential sources — restructure
       ----------------------------------------------------------------
       Left "aside" column stacks the role pill on top of the source
       thumbnail. The body holds a top-right relevance chip, then
       title / meta / contribution / limitation. Lays out cleanly
       even when the thumbnail or relevance score is missing.
    ============================================================ */
    .report-v2-source-item {
      position: relative;
      align-items: stretch;
      gap: 12px;
    }
    .report-v2-source-aside {
      flex: 0 0 auto;
      display: flex;
      flex-direction: column;
      align-items: flex-start;
      gap: 6px;
      width: 96px;
    }
    .report-v2-source-thumb {
      width: 96px;
      height: 54px;
      border-radius: 6px;
      overflow: hidden;
      background: var(--surface-mint);
    }
    .report-v2-source-thumb img {
      display: block;
      width: 100%;
      height: 100%;
      object-fit: cover;
    }
    .report-v2-source-body {
      padding-right: 90px; /* room for the relevance pill in the corner */
    }
    .report-v2-source-relevance {
      position: absolute;
      top: 10px;
      right: 12px;
      font-size: 10px;
      letter-spacing: 0.02em;
      white-space: nowrap;
    }

    /* "View all sources" — pill button reusing the "Show more questions"
       style. Strip the dark-fill treatment the legacy entry-point button
       had so the two CTAs match visually. */
    .report-v2-source-view-all-btn {
      text-transform: uppercase;
      letter-spacing: 0.06em;
    }
    .report-v2-source-view-all-btn.report-v2-ongoing-show-more {
      background: var(--surface-white);
      color: var(--ink-navy);
      border: 1px solid var(--border-cool);
    }
    .report-v2-source-view-all-btn.report-v2-ongoing-show-more:hover {
      background: var(--surface-pale-cool);
      border-color: var(--ink-cool-grey-pale);
    }

    /* Detailed Analysis — best transcripts for this section.
       The recs panel should clamp to the same max-width as the
       paragraph body (760px) so the panel doesn't extend wider than
       the prose it summarises. */
    .report-v2-detailed-recs {
      max-width: 760px;
    }

    /* Single-column source list when the cards get narrow enough that
       the body's right-padded relevance pill starts overlapping the
       contribution text. */
    @media (max-width: 720px) {
      .report-v2-source-body {
        padding-right: 0;
      }
      .report-v2-source-relevance {
        position: static;
        margin-bottom: 6px;
        display: inline-block;
      }
    }

    /* ============================================================
       Suggested follow-up transcripts
       ----------------------------------------------------------------
       These are explicitly NOT report sources — they're "what to open
       next" cards that challenge, contradict, extend, deep-dive, or
       update the report. Visual language reuses the rec-card chrome
       but adds a relationship-type chip + "Adds:" kicker so the
       reader instantly understands why this card is here.
    ============================================================ */
    .report-v2-followup-list {
      list-style: none;
      margin: 0;
      padding: 0;
      display: grid;
      grid-template-columns: 1fr;
      gap: 10px;
    }
    @media (min-width: 720px) {
      .report-v2-followup-list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    }
    .report-v2-followup-card {
      position: relative;
      display: grid;
      grid-template-columns: 116px minmax(0, 1fr);
      gap: 12px;
      padding: 10px 12px;
      padding-right: 40px; /* room for corner AI★ */
      background: var(--surface-white);
      border: 1px solid rgba(28, 51, 67, 0.1);
      border-radius: 12px;
      list-style: none;
      transition: border-color 0.16s ease, box-shadow 0.16s ease, transform 0.16s ease;
      align-items: start;
    }
    .report-v2-followup-card-clickable { cursor: pointer; }
    .report-v2-followup-card-clickable:hover,
    .report-v2-followup-card-clickable:focus-visible {
      border-color: rgba(28, 51, 67, 0.22);
      box-shadow: 0 10px 22px rgba(28, 51, 67, 0.08);
      transform: translateY(-1px);
      outline: none;
    }
    /* Left media column: thumb + meta-under-thumb (channel/speaker/date
       stacked vertically below the miniature). Same pattern Material
       Report uses for related-transcript cards. */
    .report-v2-followup-media {
      display: flex;
      flex-direction: column;
      gap: 4px;
      width: 116px;
    }
    .report-v2-followup-thumb {
      width: 116px;
      height: 66px;
      border-radius: 8px;
      overflow: hidden;
      background: var(--surface-mint);
    }
    .report-v2-followup-thumb img {
      display: block;
      width: 100%;
      height: 100%;
      object-fit: cover;
    }
    .report-v2-followup-thumb-fallback {
      display: flex; align-items: center; justify-content: center;
      width: 100%; height: 100%;
      color: var(--ink-muted); font-size: 12px; font-weight: 800;
      letter-spacing: 0.08em;
      text-transform: uppercase;
    }
    .report-v2-followup-meta-under-thumb {
      display: flex;
      flex-direction: column;
      gap: 2px;
      width: 116px;
      font-size: 10.5px;
      color: var(--ink-muted);
      font-weight: 500;
      line-height: 1.3;
    }
    .report-v2-followup-meta-line {
      display: inline-flex;
      align-items: center;
      gap: 3px;
      min-width: 0;
      color: var(--ink-muted);
      text-decoration: none;
    }
    .report-v2-followup-meta-line .entity-page-link-icon,
    .report-v2-followup-meta-line svg {
      width: 10px; height: 10px; opacity: 0.75; flex-shrink: 0;
    }
    .report-v2-followup-meta-line .report-v2-followup-meta-text {
      display: inline-block;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
      max-width: 96px;
    }
    .report-v2-followup-body {
      display: flex; flex-direction: column; gap: 4px; min-width: 0;
    }
    .report-v2-followup-rel {
      align-self: flex-start;
      font-size: 9.5px;
      margin-bottom: 2px;
    }
    .report-v2-followup-title {
      /* Bigger title, single-line clip with ellipsis — matches the
         source-package card treatment. The 2-line clamp before let long
         titles dominate the card visually; capping at one line keeps
         cards uniform-height and reads less aggressively. */
      margin: 0;
      font-size: 15px;
      font-weight: 700;
      color: var(--ink-navy);
      line-height: 1.3;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }
    /* Old inline-meta classes are no longer rendered (meta moved to
       under the thumb in the media column). Keep the class definitions
       trimmed so any stale markup still styles consistently. */
    .report-v2-followup-meta { display: none; }
    .report-v2-followup-adds {
      margin: 4px 0 0 0;
      font-size: 12px;
      line-height: 1.45;
      color: var(--ink-slate);
      display: -webkit-box;
      -webkit-line-clamp: 2;
      -webkit-box-orient: vertical;
      overflow: hidden;
      max-height: calc(1.45em * 2);
    }
    .report-v2-followup-kicker {
      font-size: 10px;
      font-weight: 900;
      letter-spacing: 0.06em;
      text-transform: uppercase;
      color: var(--ink-slate);
      margin-right: 6px;
    }
    .report-v2-followup-why {
      margin: 0;
      font-size: 12px;
      line-height: 1.5;
      color: var(--ink-slate);
    }
    .report-v2-followup-chips {
      display: flex;
      flex-wrap: wrap;
      gap: 4px;
      margin-top: 4px;
    }
    .report-v2-followup-chip {
      font-size: 10.5px;
      padding: 2px 8px;
    }
    .report-v2-followup-corner-ai {
      position: absolute;
      bottom: 8px;
      right: 8px;
      z-index: 2;
    }

    /* ============================================================
       Analyst Brief — condensed treatment in compact scenarios.
       ----------------------------------------------------------------
       Per the user spec:
         - Long  + Compact (lc): max 2-3 paragraphs, no sub-fields
         - Detailed + Compact (dc): max 3-5 paragraphs, no sub-fields
       Full modes (mf/lf/df) render everything the agent produced.
       Short scenarios (sc/sf/mc) don't show the Brief at all
       (gated upstream by data-show-in).
    ============================================================ */
    .report-v2-layout[data-length-mode="long"][data-view-mode="compact"]
      .report-v2-brief-paragraph:nth-of-type(n+4),
    .report-v2-layout[data-length-mode="long"][data-view-mode="compact"]
      .report-v2-brief-sub,
    .report-v2-layout[data-length-mode="detailed"][data-view-mode="compact"]
      .report-v2-brief-paragraph:nth-of-type(n+6),
    .report-v2-layout[data-length-mode="detailed"][data-view-mode="compact"]
      .report-v2-brief-sub {
      display: none !important;
    }

    /* ============================================================
       Legacy-payload banner — shown only when row.daily_v2 is null.
    ============================================================ */
    .report-v2-legacy-banner {
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 14px;
      flex-wrap: wrap;
      padding: 12px 18px;
      margin: 0 0 12px 0;
      border-radius: 12px;
      border: 1px dashed rgba(28, 51, 67, 0.20);
      background: var(--surface-warm-warning);
      color: var(--brand-bronze);
      font-size: 13px;
    }
    .report-v2-legacy-banner-text strong { color: var(--ink-navy); font-weight: 700; }
    .report-v2-legacy-banner-btn {
      display: inline-flex;
      align-items: center;
      padding: 5px 12px;
      border-radius: 999px;
      border: 1px solid rgba(28, 51, 67, 0.30);
      background: var(--surface-white);
      color: var(--ink-navy);
      font-size: 11.5px;
      font-weight: 700;
      letter-spacing: 0.04em;
      text-transform: uppercase;
      text-decoration: none;
      transition: background 120ms ease, border-color 120ms ease;
    }
    .report-v2-legacy-banner-btn:hover {
      background: var(--ink-navy);
      color: var(--surface-cream);
      border-color: var(--ink-navy);
    }

    /* ============================================================
       Rail "Back to Reports" link — match the material report's
       bold compact treatment so the entry/exit primitives look
       consistent across report types.
    ============================================================ */
    .report-v2-rail-back,
    .report-surface-rail-back {
      display: flex;
      align-items: center;
      gap: 6px;
      padding: 7px 10px;
      border-radius: 8px;
      background: transparent;
      color: var(--ink-navy) !important;
      font-size: 11.5px;
      font-weight: 800 !important;
      letter-spacing: 0.03em;
      text-decoration: none;
      text-transform: none;
    }
    .report-v2-rail-back:hover,
    .report-surface-rail-back:hover {
      background: var(--surface-pale-cool) !important;
      color: var(--ink-navy) !important;
    }

    /* (Follow-up thumb sizing is set on the main rule above — 116px
       media column with thumb + meta-under-thumb stacked, matching
       the Material Report pattern.) */

    /* ============================================================
       Source-package "Why it matters" snippet — restored from the
       legacy template. One short paragraph beneath the meta line
       that explains why the transcript matters for THIS report.
    ============================================================ */
    .report-v2-source-package-why {
      margin: 6px 0 0 0;
      padding-right: 40px; /* clear the bottom-right AI★ corner */
      font-size: 12px;
      line-height: 1.5;
      color: var(--ink-slate);
      display: -webkit-box;
      -webkit-line-clamp: 2;
      line-clamp: 2;
      -webkit-box-orient: vertical;
      overflow: hidden;
      text-overflow: ellipsis;
      /* Hard cap so the snippet never exceeds two lines even when the
         browser doesn't honour -webkit-line-clamp (Firefox <68 etc).
         line-height=1.5 × 2 lines = 3em. */
      max-height: 3em;
    }
    .report-v2-source-package-why-kicker {
      /* Inline so it flows in the -webkit-box clamp without bumping the
         line count off — inline-block can confuse the line counter. */
      display: inline;
      font-size: 9.5px;
      font-weight: 900;
      letter-spacing: 0.08em;
      text-transform: uppercase;
      color: var(--ink-navy);
      margin-right: 6px;
    }
    /* 2026-05-21 — Tiny "Generate analysis" affordance inside
       source-package rows that have no personal analysis yet. Sized
       to be the LEAST visually-loud element in the row — sentence
       case, small font, muted cool-grey, dotted-underline link
       affordance instead of a chip/button shell. Brightens
       slightly + solid underline on hover/focus so the click target
       is discoverable without competing with the title or the
       relevance chip. JS click handler is registered in the inline
       <script> block of partials/report_detail_v2_content.html. */
    .report-v2-source-package-generate {
      appearance: none;
      background: transparent;
      border: 0;
      padding: 2px 0;
      margin: 4px 0 0 0;
      font-family: inherit;
      font-size: 11px;
      font-weight: 500;
      line-height: 1.4;
      letter-spacing: 0;
      color: var(--ink-cool-grey, var(--ink-cool-grey));
      cursor: pointer;
      text-decoration: underline;
      text-decoration-style: dotted;
      text-decoration-thickness: 1px;
      text-underline-offset: 2px;
      transition: color 0.14s ease, text-decoration-style 0.14s ease;
      align-self: flex-start;
    }
    .report-v2-source-package-generate:hover,
    .report-v2-source-package-generate:focus-visible {
      color: var(--ink-slate, var(--ink-slate));
      outline: none;
      text-decoration-style: solid;
    }
    .report-v2-source-package-generate:disabled {
      opacity: 0.6;
      cursor: progress;
      text-decoration-style: dotted;
    }

    /* 2026-05-21 — "Generate analysis" CTA — shared across both
       surfaces that render the pill:
         - `.report-v2-source-item`         — "Most influential sources" card
         - `.report-v2-source-package-item` — source-package row
       Both get the same suggested-report-angle "Use this angle ›"
       look: sentence-case green, right-aligned at the bottom of
       the card, chevron added via ::after, no button-shell shadow.
       The base `.report-v2-source-package-generate` rule earlier in
       this file is now effectively dead for these two surfaces — its
       dotted-underline / left-align / muted-cool-grey styling is
       fully overridden here. It survives only as a fallback for any
       future surface that wants the older quiet-link look. The
       button still uses one class so the JS click handler + the
       AJAX flow stay unified.

       Resets needed because the global `a.button, button { ... }`
       rule in base_part02.css applies a primary-button shell
       (box-shadow, border-radius, filter on hover, translateY on
       hover) that the base rule didn't fully neutralize — so the
       CTA was rendering with a button-shaped shadow behind the
       text. Explicit nulls below make the button read as text +
       chevron, not a chip.

       Per-surface positioning:
         - Influential card has no bottom-right occupant → CTA at
           `right: 12px` flush with the card edge.
         - Source-package row has an AI★ corner at `right: 8px` →
           CTA at `right: 44px` to clear the AI★ button. */
    .report-v2-source-item .report-v2-source-package-generate,
    .report-v2-source-package-item .report-v2-source-package-generate {
      /* Reset the base "dotted-underline link" look. */
      text-decoration: none;
      align-self: auto;

      /* Reset the global a.button/button shell. */
      box-shadow: none;
      border-radius: 0;
      filter: none;

      /* Anchor to the bottom-right corner of the card. Both items
         are `position: relative` (line 1786 + line 2120), so
         absolute escapes the body padding. */
      position: absolute;
      bottom: 12px;
      right: 12px;
      margin: 0;
      padding: 2px 0;
      width: auto;

      font-size: 11px;
      font-weight: 600;
      letter-spacing: 0.04em;
      color: var(--positive-text-deep, #2a6b3a);
      opacity: 0.78;
      transition: opacity 0.14s ease, transform 0.14s ease, color 0.14s ease;
    }
    /* Source-package row needs to clear the AI★ corner which sits
       at `bottom: 8px; right: 8px` (~28px wide). Offset the CTA
       enough that it lands to the LEFT of the AI★ with a comfortable
       gap. */
    .report-v2-source-package-item .report-v2-source-package-generate {
      right: 44px;
    }
    .report-v2-source-item .report-v2-source-package-generate::after,
    .report-v2-source-package-item .report-v2-source-package-generate::after {
      /* nbsp + single-right-pointing-angle quotation mark — same
         glyph as `&rsaquo;` in the suggested-angle CTAs so all four
         "click-to-advance" surfaces feel like one family. */
      content: "\00A0\203A";
    }
    .report-v2-source-item .report-v2-source-package-generate:hover,
    .report-v2-source-item .report-v2-source-package-generate:focus-visible,
    .report-v2-source-package-item .report-v2-source-package-generate:hover,
    .report-v2-source-package-item .report-v2-source-package-generate:focus-visible {
      opacity: 1;
      /* `translateX(2px)` keeps the small slide cue from the
         suggested-angle CTA. Explicit override of the global button
         :hover rule that would otherwise apply `translateY(-1px)` +
         `filter: brightness(1.02)`. */
      transform: translateX(2px);
      filter: none;
      box-shadow: none;
      outline: none;
      text-decoration: none;
      color: var(--positive-text-deep, #2a6b3a);
    }
    .report-v2-source-item .report-v2-source-package-generate:disabled,
    .report-v2-source-package-item .report-v2-source-package-generate:disabled {
      opacity: 0.55;
      cursor: progress;
      transform: none;
      box-shadow: none;
      filter: none;
    }
    .report-v2-source-item .report-v2-source-package-generate:disabled::after,
    .report-v2-source-package-item .report-v2-source-package-generate:disabled::after {
      /* Drop the chevron while the button is in the in-flight
         "Generating…" state so the user doesn't get a directional
         "ready to click" cue mid-request. */
      content: "";
    }
    /* Body padding-bottom reserve when the CTA is present, so a
       long limitation / why-it-matters paragraph can never visually
       run under the absolutely-positioned CTA. Scoped with `:has()`
       so cards without the CTA keep their existing compact spacing. */
    .report-v2-source-item:has(.report-v2-source-package-generate) .report-v2-source-body,
    .report-v2-source-package-item:has(.report-v2-source-package-generate) .report-v2-source-package-body {
      padding-bottom: 28px;
    }
    /* 2026-05-21 — While the in-flight loading overlay is on the
       card (markCardOpening adds `app-card-opening`), hide the
       button entirely so the "Generate analysis ›" text doesn't
       bleed through the translucent overlay backdrop. The overlay's
       own "Generating analysis..." label is the only text the user
       sees while waiting. Per user direction: no animation / no
       label change on the button itself. `visibility: hidden`
       keeps the button's layout reservation intact (it's absolute-
       positioned, so layout impact is zero anyway), and the
       :disabled state is still applied for accessibility (ARIA +
       click-suppression). */
    .report-v2-source-item.app-card-opening .report-v2-source-package-generate,
    .report-v2-source-package-item.app-card-opening .report-v2-source-package-generate {
      visibility: hidden;
    }

    /* Source-package "X of Y selected" note. Quiet/informational. */
    .report-v2-source-selection-note {
      margin: 6px 0 14px 0;
      padding: 8px 12px;
      border-left: 3px solid var(--border-pale);
      background: var(--surface-pale-cool);
      font-size: 12.5px;
      line-height: 1.5;
      color: var(--ink-slate);
    }
    .report-v2-source-selection-tier-line {
      color: var(--ink-muted);
    }

    /* ============================================================
       Source-package KPI strip — the TRUE numbers from the selection
       algorithm. Replaces the agent's unreliable transcript_count
       claim. Four cards tell the funnel story.
    ============================================================ */
    .report-v2-source-kpis {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
      gap: 10px;
      margin: 4px 0 14px 0;
    }
    .report-v2-source-kpi {
      display: flex;
      flex-direction: column;
      gap: 2px;
      padding: 12px 14px;
      border-radius: 12px;
      background: var(--surface-pale-cool);
      border: 1px solid rgba(28, 51, 67, 0.10);
    }
    .report-v2-source-kpi-accent {
      background: linear-gradient(180deg, var(--surface-warm-warning) 0%, var(--surface-cream) 100%);
      border-color: var(--warning-border-soft);
    }
    .report-v2-source-kpi-num {
      font-size: 28px;
      font-weight: 900;
      color: var(--ink-navy);
      line-height: 1.1;
      letter-spacing: -0.01em;
    }
    .report-v2-source-kpi-accent .report-v2-source-kpi-num {
      color: var(--brand-bronze);
    }
    .report-v2-source-kpi-label {
      margin-top: 2px;
      font-size: 11.5px;
      font-weight: 700;
      letter-spacing: 0.04em;
      text-transform: uppercase;
      color: var(--ink-navy);
    }
    .report-v2-source-kpi-accent .report-v2-source-kpi-label {
      color: var(--brand-bronze);
    }
    .report-v2-source-kpi-sub {
      font-size: 11.5px;
      color: var(--ink-slate);
      line-height: 1.4;
    }
    .report-v2-source-kpi-accent .report-v2-source-kpi-sub {
      color: var(--brand-bronze);
    }

    /* Drop-reason chips: small line below the KPIs explaining why the
       funnel narrowed. Only renders when items were actually excluded. */
    .report-v2-source-kpi-dropouts {
      margin: 0 0 14px 0;
      font-size: 12px;
      color: var(--ink-muted);
      display: flex;
      flex-wrap: wrap;
      gap: 4px 10px;
      align-items: baseline;
    }
    .report-v2-source-kpi-dropouts > span:first-child {
      font-weight: 700;
      color: var(--ink-slate);
      text-transform: uppercase;
      letter-spacing: 0.06em;
      font-size: 10.5px;
    }
    .report-v2-source-kpi-drop {
      display: inline-flex;
      align-items: center;
      gap: 4px;
      padding: 2px 8px;
      border-radius: 999px;
      background: rgba(28, 51, 67, 0.06);
      color: var(--ink-slate);
    }
    .report-v2-source-kpi-drop strong { color: var(--ink-navy); }

    /* ============================================================
       Most-influential source card — meta under thumbnail
       Same pattern Material Report + Follow-up cards use: channel
       and speaker stacked vertically beneath the miniature, instead
       of inline next to the title.
    ============================================================ */
    .report-v2-source-meta-under-thumb {
      display: flex;
      flex-direction: column;
      gap: 2px;
      width: 96px;          /* match the aside thumbnail width */
      margin-top: 4px;
      font-size: 10.5px;
      color: var(--ink-muted);
      font-weight: 500;
      line-height: 1.3;
    }
    .report-v2-source-meta-line {
      display: inline-flex;
      align-items: center;
      gap: 3px;
      min-width: 0;
      color: var(--ink-muted);
      text-decoration: none;
    }
    .report-v2-source-meta-line .entity-page-link-icon,
    .report-v2-source-meta-line svg {
      width: 10px; height: 10px; opacity: 0.75; flex-shrink: 0;
    }
    .report-v2-source-meta-line .report-v2-source-meta-text {
      display: inline-block;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
      max-width: 80px;
    }
    /* Placeholder for when a source has no speaker info — keeps the
       slot height so adjacent cards (one with speaker, one without)
       still line up. visibility: hidden preserves layout; the
       &nbsp; gives the empty span an actual line-box. */
    .report-v2-source-meta-line-empty {
      visibility: hidden;
      min-height: 1em;
    }

    /* -----------------------------------------------------------------
       Hover lift animation — applied across the report's clickable /
       scannable cards. Same transform + box-shadow pattern used by
       .report-v2-implication-card so all card families feel consistent.
       Cards with their own per-tone borders (niche, change items) keep
       those — we only animate transform/shadow/border-color subtly.
       ----------------------------------------------------------------- */
    .report-v2-exec-card,
    .report-v2-change-item,
    .report-v2-driver-item,
    .report-v2-niche-item,
    .report-v2-tracked-item,
    .report-v2-ongoing-item,
    .report-v2-evidence-col,
    .report-v2-next-item,
    .report-v2-source-kpi,
    .report-v2-source-item {
      transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
    }
    .report-v2-exec-card:hover,
    .report-v2-change-item:hover,
    .report-v2-driver-item:hover,
    .report-v2-niche-item:hover,
    .report-v2-tracked-item:hover,
    .report-v2-ongoing-item:hover,
    .report-v2-evidence-col:hover,
    .report-v2-next-item:hover,
    .report-v2-source-kpi:hover,
    .report-v2-source-item:hover {
      transform: translateY(-2px);
      border-color: rgba(28, 51, 67, 0.18);
      box-shadow: 0 10px 22px rgba(28, 51, 67, 0.08);
    }
    /* Clickable Most-influential-source card: cursor + slightly stronger
       lift to signal it opens the underlying transcript. The card-open
       overlay (.app-card-open-overlay, ::after dim) lives in base.css
       and is applied by base_shell.js's markCardOpening helper. */
    .report-v2-source-item-clickable {
      cursor: pointer;
    }
    .report-v2-source-item-clickable:hover {
      transform: translateY(-3px);
      box-shadow: 0 14px 28px rgba(28, 51, 67, 0.12);
    }
    .report-v2-source-item-clickable:focus-visible {
      outline: 2px solid var(--ink-navy);
      outline-offset: 2px;
    }
    /* Allow the card-open overlay (positioned absolutely) to sit inside
       the LI without leaking out. The overlay class itself sets the
       backdrop styling — we just need a positioning context here. */
    .report-v2-source-item { position: relative; }

    /* -----------------------------------------------------------------
       Print / Save-as-PDF button in the hero. Small chip, matches the
       AI-star look so the two sit comfortably together. Hidden in print.
       ----------------------------------------------------------------- */
    .report-v2-print-btn {
      display: inline-flex; align-items: center; gap: 6px;
      padding: 6px 12px;
      border-radius: 999px;
      border: 1px solid rgba(28, 51, 67, 0.18);
      background: var(--surface-white);
      color: var(--ink-navy);
      font-size: 12px; font-weight: 700; letter-spacing: 0.04em;
      text-transform: uppercase;
      cursor: pointer;
      transition: background 0.16s ease, border-color 0.16s ease, transform 0.16s ease, box-shadow 0.16s ease;
    }
    .report-v2-print-btn svg { width: 14px; height: 14px; display: block; }
    .report-v2-print-btn:hover,
    .report-v2-print-btn:focus-visible {
      background: var(--surface-pale-cool);
      border-color: var(--ink-navy);
      transform: translateY(-1px);
      box-shadow: 0 4px 10px rgba(28, 51, 67, 0.10);
      outline: none;
    }

    /* =================================================================
       Print stylesheet — when the user picks "Print / PDF" or hits
       Cmd/Ctrl+P, strip out the non-content chrome so the printed PDF
       reads like a research note, not a screenshot of the app.

       The button in the hero calls `setMode('full')` and opens every
       <details> before invoking `window.print()`, so we don't have to
       reverse compact-mode CSS here.
       ================================================================= */
    @media print {
      /* Page setup: portrait, sensible margins, no headers/footers
         (most browsers respect this — Chrome shows it in the dialog). */
      @page { size: auto; margin: 14mm 12mm; }

      html, body {
        background: var(--surface-white) !important;
        color: var(--ink-darkest) !important;
      }

      /* Hide every shell chrome element that doesn't belong on paper.
         Left rail, view toggle, hero action row, feedback section,
         AI prompts, compact-CTA strip, deep-link query params, etc. */
      .app-shell-topbar,
      .app-shell-topbar-with-extension,
      .app-shell-sidebar,
      #app-shell-sidebar-overlay,
      .app-shell-route-loading,
      #app-fullscreen-loading-overlay,
      .report-v2-rail,
      .report-v2-view-toggle,
      .report-v2-hero-actions,
      .report-v2-print-btn,
      .report-v2-compact-cta,
      .report-v2-feedback-card,
      .report-v2-legacy-banner,
      .ai-star,
      [data-ai-prompt],
      .report-v2-track-btn,
      .report-v2-source-package-summary-toggle,
      .report-v2-source-controls,
      .report-v2-source-package-summary-count,
      .report-v2-niche-toggle-wrap,
      .report-v2-ongoing-show-more,
      .report-v2-source-kpi-dropouts,
      .report-v2-tab-strip,
      .report-v2-rail-back {
        display: none !important;
      }

      /* The layout shell uses a sidebar grid; drop that so the report
         body uses the full printable width. */
      .report-v2-layout,
      .report-v2-shell {
        display: block !important;
        max-width: 100% !important;
        width: 100% !important;
        margin: 0 !important;
        padding: 0 !important;
      }
      .report-v2-shell { padding: 0 !important; }

      /* Cards lose their drop-shadows + lift transforms and pick up a
         thin border instead — looks crisper on paper than a shadow. */
      .report-v2-card {
        background: var(--surface-white) !important;
        border: 1px solid var(--border-cool) !important;
        box-shadow: none !important;
        transform: none !important;
        margin: 0 0 10mm 0 !important;
        padding: 10mm 8mm !important;
        page-break-inside: avoid;
        break-inside: avoid;
      }
      .report-v2-card-head { margin-bottom: 4mm; }
      .report-v2-card-title { font-size: 14pt !important; }
      .report-v2-card-body { font-size: 10.5pt; }

      /* Hero block prints as the cover — bigger title, generated-on
         line, no chips animation. */
      .report-v2-hero { border: 0 !important; padding: 0 0 6mm 0 !important; margin: 0 !important; }
      .report-v2-hero-title { font-size: 22pt !important; line-height: 1.2; }
      .report-v2-hero-meta { font-size: 9pt; color: var(--ink-slate) !important; }

      /* Disable all motion / animations so nothing prints mid-frame. */
      *,
      *::before,
      *::after {
        animation: none !important;
        transition: none !important;
      }
      .report-v2-tm-cell:not(.report-v2-tm-cell-empty) .report-v2-tm-dot {
        animation: none !important;
        transform: scale(1.1) !important;
      }

      /* Clickable cards lose their cursor hint + lift transform. */
      .report-v2-rec-card-clickable,
      .report-v2-source-item-clickable {
        cursor: default !important;
        transform: none !important;
        box-shadow: none !important;
      }

      /* Always show every <details> as if expanded — the JS opens them
         before printing, but the print stylesheet forces it too in case
         the browser short-circuits the JS. */
      details { display: block !important; }
      details > summary { display: none !important; }

      /* Make link URLs print after the link text for anchors that point
         out of the report. Internal section anchors are noisy on paper,
         so only annotate external + /review/ + /transcript/ paths. */
      a[href^="/review/"]::after,
      a[href^="/transcript/"]::after,
      a[href^="http"]::after {
        content: " (" attr(href) ")";
        font-size: 8pt;
        color: var(--ink-slate);
        word-break: break-all;
      }

      /* Avoid orphan widgets — keep headings with their first line. */
      h1, h2, h3 { break-after: avoid; page-break-after: avoid; }
      ul, ol { break-inside: avoid; page-break-inside: avoid; }
    }

/* ============================================================
   Per-user source-state markers — V2 refinement (top-right cluster).
   - Stacked under the Relevance chip in the top-right corner so
     users find them where they already look for card status.
   - Favorite uses a FILLED bronze pill — strongest visual cue.
   - Reviewed uses a calmer mint pill — present but quieter.
   - Favorited cards get a 3px bronze inset rail on the left edge
     (and a subtle warm cream tint hugging the rail) so the card
     reads as "personal favorite" at one glance.
   ============================================================ */

/* Top-right status cluster: relevance chip + personal-state pills. */
.report-v2-source-package-status {
  position: absolute;
  top: 10px;
  right: 12px;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 6px;
  z-index: 2;
  pointer-events: none;
}
.report-v2-source-package-status .report-v2-source-package-relevance {
  position: static;
  margin: 0;
  pointer-events: auto;
}
.report-v2-source-personal-state {
  display: inline-flex;
  gap: 4px;
  pointer-events: auto;
}

/* Pills themselves. */
.report-v2-source-state-pill {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  padding: 3px 9px 3px 7px;
  border-radius: 999px;
  border: 1px solid transparent;
  line-height: 1.3;
  white-space: nowrap;
}
.report-v2-source-state-icon { font-size: 11px; line-height: 1; }

/* Both pills share the same outline-style system — only icon + color
   tokens differ. Favorite uses bronze, Reviewed uses muted green.
   2026-05-18: aligned the visual weight of both pills so they read as
   two states of the same system. The original `surface-cream-soft`
   background on Favorite was reading much warmer than the mint on
   Reviewed; both now use a low-opacity tint of their own accent color
   so saturation levels match. The card identity is set by the
   pill — no filled gradients, no shadows, no oversized icons. */
.report-v2-source-state-pill.is-favorite {
  background: rgba(122, 77, 10, 0.08);
  color: var(--brand-bronze);
  border-color: rgba(122, 77, 10, 0.22);
}
.report-v2-source-state-pill.is-favorite .report-v2-source-state-icon {
  color: var(--brand-bronze);
}
.report-v2-source-state-pill.is-reviewed {
  background: var(--surface-mint);
  color: var(--positive-text-deep);
  border-color: var(--surface-mint-deep);
}
.report-v2-source-state-pill.is-reviewed .report-v2-source-state-icon {
  color: var(--positive-border-dark);
}

/* Read-later toggle: icon-only (drop the "Read later" / "Saved" text), and on
   hover-capable devices reveal it only while the source card is hovered —
   unless it's already saved or keyboard-focused (so the saved state stays
   visible and it's reachable without a mouse). Uses opacity, not display, so
   the slot is reserved and hovering doesn't shift the other markers. On touch
   devices (no hover) it stays visible. */
.report-v2-source-read-later .report-v2-source-state-label { display: none; }
.report-v2-source-read-later { padding-left: 7px; padding-right: 7px; }
@media (hover: hover) {
  .report-v2-source-read-later { opacity: 0; transition: opacity 0.15s ease; }
  .report-v2-source-package-item:hover .report-v2-source-read-later,
  .report-v2-source-read-later.is-active,
  .report-v2-source-read-later:focus-visible { opacity: 1; }
}

/* Card-level accents -------------------------------------------------
   2026-05-18: Reviewed no longer gets a top-edge inset — per the
   refined marker spec, Reviewed is pill-only and never touches the
   card chrome. Favorite still gets a 2px bronze rail on the LEFT
   edge (the user's stated upper limit). That keeps the favorited
   card slightly more discoverable than reviewed without changing
   the card's identity — the pill in the top-right corner does most
   of the signaling. */
.report-v2-source-package-item { position: relative; }

.report-v2-source-package-item.is-favorited {
  box-shadow: inset 2px 0 0 var(--brand-bronze);
}

/* Mobile: collapse labels to icons only so the top-right cluster
   doesn't crowd the Relevance chip when the card is narrow. */
@media (max-width: 560px) {
  .report-v2-source-state-label { display: none; }
  .report-v2-source-state-pill { padding: 3px 7px; }
  .report-v2-source-package-status { top: 8px; right: 8px; gap: 4px; }
}
