/* ═══════════════════════════════════════════════════════════════════════════
   RENATUS REPORT — SHARED CHART COMPONENTS
   File: static/css/report/charts.css

   Shared library. Every chart component usable by any report template.
   Naming convention: prefix describes the component, never the report slug.
   All values use design tokens — zero hardcoded colours or sizes.

   COMPONENT INDEX
   ───────────────────────────────────────────────────────────────────────────
   SECTION SCAFFOLDING
     .mi-section            Section wrapper (continuous-scroll)
     .mi-eyebrow            Section category label
     .mi-title              Section heading
     .mi-standfirst         Opening pull-quote paragraph
     .mi-body               Body paragraph
     .mi-src                Inline source superscript
     .mi-divider            Section separator rule
     .mi-figure             Chart/figure block wrapper
     .mi-figure-title       Chart headline (finding, not topic)
     .mi-figure-sub         Chart subtitle / scope line
     .mi-figure-source      Per-figure attribution line
     .mi-analyst (S4)       Analyst's View callout (dark bg)

   STAT COMPONENTS
     .mi-stat-cards         2-up stat card grid
     .mi-stat-card          Individual stat card
     .mi-stat-callout-grid  Callout grid (big left-border numbers)
     .mi-stat-callout       Individual callout

   CHART COMPONENTS
     C1  .mi-seg-*          Segmented bar (composition/share)
     C2  (see stat callouts above)
     C3  .mi-waterfall-*    Waterfall / revenue bridge
     C3b .mi-line-*         SVG line trend chart
     C4  .mi-hbar-*         Horizontal bar (rankings)
     C5  .mi-twobar-*       Two-bar + multiplier
     C7  .mi-dot-*          Dot plot (geographic / entity spread)
     T2  .scorecard         Scorecard table (pip scores + badges)
     T3  .mi-heatmap        Heat map table

   STRUCTURAL COMPONENTS
     S1  .mi-timeline-*     Horizontal above/below-axis timeline
     S2  .mi-capital-*      Capital event cards (2×2 grid)
     .mi-key-findings       Numbered key findings list
     .mi-intel-grid         2-column intelligence brief grid
     .mi-meta-line          Report identity meta bar
     .mi-sources-section    Sources & methodology section

   REPORT CONTEXT OVERRIDES
     .report-container.*    Split-screen panel overrides

   PRINT OVERRIDES
   ═══════════════════════════════════════════════════════════════════════════ */


/* ───────────────────────────────────────────────────────────────────────────
   SECTION SCAFFOLDING
   ─────────────────────────────────────────────────────────────────────────── */

.mi-section {
  padding: 0;
  max-width: var(--report-page-w);
  margin: 48px auto 0;
}

.mi-section:last-child {
  padding-bottom: var(--spacing-12);
}

.mi-eyebrow {
  display: block;
  font-size: var(--text-xl);
  font-weight: var(--font-weight-bold);
  letter-spacing: normal;
  color: var(--cyan);
  /* No top margin — the eyebrow is the first child of the section card,
     whose 28px padding already sets the top gap. Christine 29 May 2026. */
  margin-top: 0;
  margin-bottom: var(--spacing-2);
}


/* Inline synth-source tag — inherits all type properties from its
   parent prose context. See note in frame.css. ── */
.mi-src {
  vertical-align: baseline;
  line-height: inherit;
  margin-left: 0.5em;
}

.mi-figure {
  border-top: 1px solid var(--report-border);
  border-bottom: 1px solid var(--report-border);
  padding: var(--spacing-8) 0;
  margin: var(--spacing-6) 0;
}

.mi-figure-title {
  font-size: 18px;
  font-weight: var(--chart-heading-wt);
  color: var(--chart-heading-color);
  line-height: 1.4;
  margin-bottom: var(--spacing-3);
}

.mi-figure-sub {
  font-size: var(--t-body);
  font-weight: var(--font-weight-normal);
  color: var(--report-ink);
  margin-bottom: var(--spacing-5);
}

.mi-figure-source {
  font-size: var(--t-small);
  color: var(--report-ink);
  line-height: 1.5;
  margin-top: var(--spacing-3);
}

.mi-figure-content {
  padding: 20px 0;
}

.mi-divider {
  display: block;
  width: 600px;
  height: 1px;
  background: var(--report-ink-35);
  margin: var(--spacing-12) auto 0;
}

/* S4 — Analyst's View callout */
.mi-analyst {
  background: var(--report-ink);
  border-radius: var(--radius-sm);
  padding: var(--spacing-4) var(--spacing-5);
  margin: var(--spacing-4) 0;
}

.mi-analyst-label {
  display: block;
  font-size: var(--t-small);
  font-weight: var(--font-weight-medium);
  letter-spacing: 1.2px;
  color: rgba(255, 255, 255, 0.45);
  margin-bottom: var(--spacing-2);
}

.mi-analyst-body {
  font-size: var(--t-small);
  line-height: 1.75;
  color: rgba(255, 255, 255, 0.88);
}


/* ───────────────────────────────────────────────────────────────────────────
   STAT COMPONENTS
   ─────────────────────────────────────────────────────────────────────────── */

/* 2-up stat card grid */
.mi-stat-cards {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--spacing-6);
  margin-bottom: var(--spacing-4);
}

.mi-stat-card,
.mi-stat-card.hl {
  /* White floating-card chrome — matches stat-callout so the stat families
     read as one. In the split render the cards float bare on the gray canvas
     (section paint stripped via .mi-section--bare), so a white fill + the
     same soft section shadow is needed for them to read against it with the
     same lift as every other section card. */
  background: var(--white);
  border: none;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-section);
  padding: var(--spacing-4);
  min-height: 88px;
}

/* In the split render the grid is the only child of a bare section; the
   section margins already provide the gap, so drop the grid's own outer
   margin to keep the cards tight under the heading card. */
.mi-section--bare > .mi-stat-cards,
.mi-section--bare > .mi-stat-callout-grid {
  margin: 0;
}

.mi-stat-card.hl .mi-stat-card-label { color: var(--report-ink); }
.mi-stat-card.hl .mi-stat-card-value { color: var(--cyan); }

/* Canonical card label/value/note recipe — shared by mi-stat-card,
   mi-stat-callout (charts.css ~245) and mi-capital-card (charts.css
   ~1340). Three components, ONE recipe. Do not re-size or re-weight
   per component. Tokens live in tokens/typography.css. */
/* Compact vertical rhythm across all three card families: label → value
   = 4px, value → note = 2px. No min-height padding. */
.mi-stat-card-label {
  display: block;
  font-size: var(--card-heading-size);
  font-weight: var(--card-heading-weight);
  letter-spacing: var(--card-heading-spacing);
  color: var(--card-heading-color);
  margin: 0 0 4px;
  line-height: 1.3;
}

.mi-stat-card-value {
  display: block;
  font-size: var(--card-value-size);
  font-weight: var(--font-weight-bold);
  font-variant-numeric: tabular-nums;
  letter-spacing: normal;
  line-height: 1.15;
  color: var(--cyan);
  margin: 0;
}

.mi-stat-card-value.grad {
  background: var(--gradient-horizontal);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}

.mi-stat-card-note {
  display: block;
  font-size: var(--card-source-size);
  font-weight: 300;
  letter-spacing: normal;
  color: var(--card-source-color);
  line-height: 1.4;
  margin: 2px 0 0;
}

/* C2 — Stat callout grid (large left-border numbers).
   Stacked vertically (single column) per design — May 14 2026.
   Mobile media query below converts to a horizontal swipe carousel
   on screens ≤ 600px and is intentionally unchanged. */
.mi-stat-callout-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--spacing-6);
  margin: var(--spacing-6) 0;
}
@media (max-width: 900px) {
  .mi-stat-callout-grid {
    grid-template-columns: 1fr;
  }
}

/* White floating card — matched to the capital-cards chrome (white fill,
   no border, container padding) so stat callouts and capital cards read as
   one family. Uses the same soft section shadow as the painted section cards
   so the bare floating cards lift the same amount. The value reads in cyan. */
.mi-stat-callout {
  background: var(--white);
  border: 1px solid var(--report-border);
  border-radius: var(--radius-lg);
  box-shadow: none;
  padding: var(--report-container-pad-y) var(--report-container-pad-x);
}


.mi-stat-callout-label {
  font-size: var(--card-heading-size);
  font-weight: var(--card-heading-weight);
  letter-spacing: var(--card-heading-spacing);
  color: var(--card-heading-color);
  line-height: 1.3;
  margin: 0 0 var(--spacing-1);
}


.mi-stat-callout-value {
  font-size: var(--card-value-size);
  font-weight: var(--font-weight-bold);
  font-variant-numeric: tabular-nums;
  letter-spacing: normal;
  color: var(--cyan);
  line-height: 1.15;
  margin: 0;
  padding-top: var(--spacing-5);
  text-transform: none;
}

.mi-stat-callout.hl {
  background: var(--white);
}
.mi-stat-callout.hl .mi-stat-callout-value { color: var(--cyan); }

/* When the value is a score (NN/100 via score_smart) it renders inside
   .rpt-score, whose canonical recipe shrinks it to 15px and weights the
   number 500 / suffix 300. Inside a stat callout the score must read at the
   same size + weight as every other callout value (with the number in cyan),
   so override the canonical recipe here. */
.mi-stat-callout-value .rpt-score { font-size: var(--card-value-size) !important; }
.mi-stat-callout-value .rpt-score .rpt-score-n {
  color: var(--cyan) !important;
  font-weight: var(--font-weight-bold) !important;
}
.mi-stat-callout-value .rpt-score .sv-score-suffix {
  font-size: var(--card-value-size) !important;
  font-weight: var(--font-weight-bold) !important;
}

.mi-stat-callout-note {
  font-size: var(--card-source-size);
  font-weight: 300;
  letter-spacing: normal;
  color: var(--card-source-color);
  line-height: 1.4;
  margin: var(--spacing-2xs) 0 0;
}

/* C2 — Mobile: convert grid to a horizontal swipe carousel.
   The desktop auto-fit grid collapses into one column on phones with a
   48px row gap, leaving large empty bands of vertical whitespace between
   cards. Switch to a horizontal scroll-snap row instead so all callouts
   stay grouped and the user swipes between them. Each card is sized so
   the next one peeks in from the right edge as a visible affordance. */
@media (max-width: 600px) {
  .mi-stat-callout-grid {
    display: flex;
    flex-wrap: nowrap;
    gap: 12px;
    overflow-x: auto;
    overflow-y: visible;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    padding-bottom: 4px;
  }
  .mi-stat-callout-grid::-webkit-scrollbar {
    display: none;
  }
  .mi-stat-callout-grid > .mi-stat-callout {
    flex: 0 0 82%;
    min-width: 0;
    margin-bottom: 0;
    scroll-snap-align: start;
  }
}


/* ═══════════════════════════════════════════════════════════════════════════
   C1 — SEGMENTED BAR
   Composition summing to 100%. Survey distributions. Population breakdowns.
   ═══════════════════════════════════════════════════════════════════════════ */

.mi-seg-bar {
  display: flex;
  width: 100%;
  height: 14px;
  border-radius: var(--radius-sm);
  overflow: hidden;
}

.mi-seg-segment {
  height: 100%;
  /* Fallback for any segment past rank-16 (the palette below covers 1-16);
     keeps an undefined rank visible rather than transparent. Christine,
     2 June 2026. Was: no base background, so rank-7+ used to disappear. */
  background: var(--gray-light);
}

/* Categorical palette by rank — a 16-colour spread across the kicker
   spectrum, so composition charts with many segments (these reports can run
   well past five) get a DISTINCT colour per segment instead of falling back
   to grey at rank-6. Segments are share-sorted desc, so rank-1 is always the
   leader. Ranks 1-5 unchanged; ranks 6-16 interleave the remaining kicker
   tokens for high contrast between neighbours. Christine, 2 June 2026.
   Was: only ranks 1-5 coloured, rank-6 grey. */
.mi-seg-segment.rank-1  { background: var(--kicker05); }
.mi-seg-segment.rank-2  { background: var(--kicker01); }
.mi-seg-segment.rank-3  { background: var(--kicker02); }
.mi-seg-segment.rank-4  { background: var(--kicker07); }
.mi-seg-segment.rank-5  { background: var(--kicker10); }
.mi-seg-segment.rank-6  { background: var(--kicker16); }
.mi-seg-segment.rank-7  { background: var(--kicker04); }
.mi-seg-segment.rank-8  { background: var(--kicker13); }
.mi-seg-segment.rank-9  { background: var(--kicker03); }
.mi-seg-segment.rank-10 { background: var(--kicker12); }
.mi-seg-segment.rank-11 { background: var(--kicker06); }
.mi-seg-segment.rank-12 { background: var(--kicker15); }
.mi-seg-segment.rank-13 { background: var(--kicker08); }
.mi-seg-segment.rank-14 { background: var(--kicker14); }
.mi-seg-segment.rank-15 { background: var(--kicker09); }
.mi-seg-segment.rank-16 { background: var(--kicker11); }

.mi-seg-callouts {
  display: flex;
  gap: var(--spacing-2) var(--spacing-6);
  flex-wrap: wrap;
  margin-top: var(--spacing-4);
  margin-bottom: 30px;
}

.mi-seg-callout {
  font-size: var(--t-small);
  font-weight: var(--font-weight-light);
  color: var(--report-ink);
  line-height: 1.5;
}

.mi-seg-callout-name {
  display: inline;
  font-size: var(--chart-name-size);
  font-weight: var(--font-weight-light);
  color: var(--chart-name-color);
}

.mi-seg-callout-share {
  display: inline;
  margin-left: var(--spacing-1);
  font-size: var(--chart-val-size);
  color: var(--report-ink);
}

/* Legend dot — color matches rank, sits inline with name */
.mi-seg-callout-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  margin-right: 6px;
  vertical-align: middle;
  position: relative;
  top: -1px;
  background: var(--report-border);
}
/* Legend dots mirror the segment palette above (rank → same kicker token), so
   each callout dot matches its bar segment. Christine, 2 June 2026. Was: only
   ranks 1-5 coloured, rank-6 grey. */
.mi-seg-callout.rank-1  .mi-seg-callout-dot { background: var(--kicker05); }
.mi-seg-callout.rank-2  .mi-seg-callout-dot { background: var(--kicker01); }
.mi-seg-callout.rank-3  .mi-seg-callout-dot { background: var(--kicker02); }
.mi-seg-callout.rank-4  .mi-seg-callout-dot { background: var(--kicker07); }
.mi-seg-callout.rank-5  .mi-seg-callout-dot { background: var(--kicker10); }
.mi-seg-callout.rank-6  .mi-seg-callout-dot { background: var(--kicker16); }
.mi-seg-callout.rank-7  .mi-seg-callout-dot { background: var(--kicker04); }
.mi-seg-callout.rank-8  .mi-seg-callout-dot { background: var(--kicker13); }
.mi-seg-callout.rank-9  .mi-seg-callout-dot { background: var(--kicker03); }
.mi-seg-callout.rank-10 .mi-seg-callout-dot { background: var(--kicker12); }
.mi-seg-callout.rank-11 .mi-seg-callout-dot { background: var(--kicker06); }
.mi-seg-callout.rank-12 .mi-seg-callout-dot { background: var(--kicker15); }
.mi-seg-callout.rank-13 .mi-seg-callout-dot { background: var(--kicker08); }
.mi-seg-callout.rank-14 .mi-seg-callout-dot { background: var(--kicker14); }
.mi-seg-callout.rank-15 .mi-seg-callout-dot { background: var(--kicker09); }
.mi-seg-callout.rank-16 .mi-seg-callout-dot { background: var(--kicker11); }


/* ═══════════════════════════════════════════════════════════════════════════
   C3 — WATERFALL CHART
   Revenue bridge, P&L decomposition, cost build-up.
   ═══════════════════════════════════════════════════════════════════════════ */

/* Waterfall-only: its top axis labels sit high, so the figure title needs a
   touch more breathing room than the shared default — scoped via :has() so no
   other chart's title spacing changes. 20px = --spacing-5. */
.mi-figure-title:has(+ .mi-waterfall-wrap) { margin-bottom: var(--spacing-5); }

.mi-waterfall-wrap {
  position: relative;
  padding-bottom: 120px;
  overflow: visible;
}

.mi-waterfall {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  /* Single source for the inter-column gap so the connector width can match. */
  --waterfall-gap: 20px;
  gap: var(--waterfall-gap);
  height: 200px;
  position: relative;
}

.mi-waterfall-baseline {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  height: 1px;
  background: var(--report-border);
}

.mi-waterfall-col {
  display: flex;
  flex-direction: column;
  align-items: center;
  flex: 0 0 50px;
  width: 50px;
  position: relative;
  height: 100%;
  justify-content: flex-end;
}

.mi-waterfall-spacer {
  width: 100%;
  background: transparent;
}

.mi-waterfall-bar {
  /* Absolutely positioned; `bottom` + `height` set inline per bar. */
  position: absolute;
  left: 0;
  right: 0;
  z-index: 1;
  border-radius: var(--radius-sm) var(--radius-sm) 0 0;
}
/* Bars that hang below the plan line: rounded at the bottom, flat at the top. */
.mi-waterfall-bar.is-down {
  border-radius: 0 0 var(--radius-sm) var(--radius-sm);
}

/* Colour system: green = positive, pink = negative, cyan = total/hl anchors,
   grey = neutral (decomposition steps with no favourable/adverse dimension).
   Gradient from 5% opacity at top → 70% at bottom so bars feel grounded.
   Christine, 12 Jun 2026. Was: solid fills.
   neutral added 16 Jun 2026 for contribution-margin decomposition. */
.mi-waterfall-bar.total    { background: linear-gradient(to bottom, color-mix(in srgb, var(--cyan)     5%, transparent), color-mix(in srgb, var(--cyan)     70%, transparent)); border: none; }
.mi-waterfall-bar.positive { background: linear-gradient(to bottom, color-mix(in srgb, var(--green)    5%, transparent), color-mix(in srgb, var(--green)    70%, transparent)); border: none; }
.mi-waterfall-bar.negative { background: linear-gradient(to bottom, color-mix(in srgb, var(--pink)     5%, transparent), color-mix(in srgb, var(--pink)     70%, transparent)); border: none; }
.mi-waterfall-bar.neutral  { background: linear-gradient(to bottom, color-mix(in srgb, var(--gray-mid) 5%, transparent), color-mix(in srgb, var(--gray-mid) 70%, transparent)); border: none; }
.mi-waterfall-bar.hl       { background: linear-gradient(to bottom, color-mix(in srgb, var(--cyan)     5%, transparent), color-mix(in srgb, var(--cyan)     70%, transparent)); border: none; opacity: 1; }
.mi-waterfall-bar.hl.is-anchor { background: linear-gradient(to bottom, color-mix(in srgb, var(--cyan) 5%, transparent), color-mix(in srgb, var(--cyan) 70%, transparent)); }

.mi-waterfall-val {
  position: absolute;
  top: -20px;
  left: 50%;
  transform: translateX(-50%);
  font-size: var(--chart-val-size);
  font-weight: var(--chart-val-wt);
  color: var(--chart-val-color);
  white-space: nowrap;
}

/* Val text is always ink — base .mi-waterfall-val rule handles it.
   Type-specific color overrides removed: bar fill carries the semantic, text doesn't repeat it.
   Total column gets bolded text (val + label) — see selectors below. */
.mi-waterfall-bar.total .mi-waterfall-val,
.mi-waterfall-col:has(.mi-waterfall-bar.total) > .mi-waterfall-val,
.mi-waterfall-col:has(.mi-waterfall-bar.total) > .mi-waterfall-label {
  font-weight: var(--font-weight-semibold);
}

.mi-waterfall-label {
  position: absolute;
  top: calc(100% + 10px);
  right: 50%;
  transform: rotate(-90deg);
  transform-origin: right center;
  font-size: var(--chart-name-size);
  font-weight: var(--chart-name-wt);
  color: var(--chart-name-color);
  line-height: 1;
  white-space: normal;
  width: 110px;
  text-align: right !important;
}

/* Thin dashed bridge from each bar to the next at the carry (running-total)
   level. Sits in the gap between columns; `bottom` is set inline per bar. */
.mi-waterfall-connector {
  position: absolute;
  left: 100%;
  width: var(--waterfall-gap);
  height: 0;
  border-top: 1px dashed var(--report-border);
  z-index: 0;
}


/* ── fw-plan-actual — Variance-from-plan chart ────────────────────────────
   Bars are FIXED HEIGHT (categorical). Every area has equal visual weight
   regardless of absolute variance size — magnitude lives in the label.
   Colour = business impact (row.fav): revenue miss + cost overrun = pink.
   Fav bars grow UP from the plan baseline; adv bars hang DOWN from it.
   ──────────────────────────────────────────────────────────────────────── */

.fw-pa-wrap { width: 100%; padding-top: 0; }

.fw-pa-legend {
  display: flex; gap: 20px; margin-top: 14px; align-items: center; justify-content: center;
}
.fw-pa-legend-item {
  display: flex; align-items: center; gap: 6px;
  font-size: 11px; color: var(--navy);
}
.fw-pa-legend-swatch {
  width: 12px; height: 12px; border-radius: 2px;
  flex-shrink: 0;
}
.fw-pa-legend-swatch--plan { background: var(--gray-light); border: 1px solid var(--report-border); }
.fw-pa-legend-swatch--fav  { background: var(--green); }
.fw-pa-legend-swatch--adv  { background: var(--band-developing); }

.fw-pa-legend-dot {
  width: 10px; height: 10px; border-radius: 50%;
  flex-shrink: 0;
}
.fw-pa-legend-dot--actual { background: var(--gray-dark); border: 2px solid white; outline: 1px solid var(--gray-mid); }

.fw-pa-chart {
  display: flex; align-items: flex-start;
  gap: 0; width: 100%;
}

.fw-pa-col {
  display: flex; flex-direction: column; align-items: center;
  flex: 1; min-width: 0;
  padding: 0 4px;
}

.fw-pa-col--total {
  border-left: 1px dashed var(--gray-light);
  margin-left: 12px;
  padding-left: 12px;
}

.fw-pa-bar-area {
  position: relative;
  width: calc(100% - 8px);
  height: 120px;
  overflow: visible;
}

/* Plan baseline — continuous horizontal rule at the zero-variance line.
   Bleeds into column padding (left/right: -4px) so segments from adjacent
   columns connect into one unbroken line across the full chart width.
   Positioned via bottom: 40% to match the template's plan_pct constant. */
.fw-pa-baseline {
  position: absolute;
  bottom: 40%; left: -4px; right: -4px;
  height: 2px;
  background: var(--navy);
  opacity: 0.15;
  z-index: 1;
}

.fw-pa-var-seg {
  position: absolute; left: 0; right: 0;
  z-index: 2;
}
/* Fav bars grow upward — 20% at plan line, 100% at tip. */
.fw-pa-var-seg.fav {
  background: linear-gradient(to top,
    color-mix(in srgb, var(--green) 20%, transparent),
    var(--green));
  border-radius: 3px 3px 0 0;
}
/* Adv bars hang downward — 20% at plan line, 100% at tip. */
.fw-pa-var-seg.adv {
  background: linear-gradient(to bottom,
    color-mix(in srgb, var(--band-developing) 20%, transparent),
    var(--band-developing));
  border-radius: 0 0 3px 3px;
}
/* Net (total) column — solid brand colours, no gradient. */
.fw-pa-col--total .fw-pa-var-seg.fav { background: var(--green); }
.fw-pa-col--total .fw-pa-var-seg.adv { background: var(--pink); }

.fw-pa-var-label {
  position: absolute; left: 50%;
  font-size: 10px; font-weight: 500; color: var(--navy); white-space: nowrap;
  transform: translateX(-50%);
  z-index: 4;
}
.fw-pa-var-label.fav { color: var(--navy); }
.fw-pa-var-label.adv { color: var(--navy); }

.fw-pa-plan-val {
  margin-top: 6px;
  font-size: 9px; color: var(--navy);
  text-align: center; white-space: nowrap;
}

.fw-pa-col-label {
  margin-top: 6px;
  font-size: 10px; font-weight: 300; color: var(--navy);
  text-align: center; line-height: 1.3;
  max-width: 72px;
  min-height: 2.6em;
  display: flex; align-items: flex-start; justify-content: center;
}
.fw-pa-col--total .fw-pa-col-label { font-weight: 600; }

.fw-pa-rule {
  border: none;
  border-top: 1px solid var(--report-border);
  margin: 14px 0 50px;
}

@media print {
  .fw-pa-bar-area { height: 140px; }
}


/* ═══════════════════════════════════════════════════════════════════════════
   C3c — DIVERGING RANGE CHART (opposing gross movements)
   Used in masked-variance / buried_variances sections.
   Two halves (negative left, positive right) split at a centre spine.
   Range bands = model-supplied low → high, never parsed from prose.
   Mobile (≤600px): axis bands hidden; label + value text stacks.
   ═══════════════════════════════════════════════════════════════════════════ */

.fw-divrange-item { margin-bottom: var(--spacing-5); }

.fw-divrange-area {
  font-size: var(--t-eyebrow);
  font-weight: 600;
  color: var(--navy);
  margin-bottom: var(--spacing-3);
  padding-top: 30px;
}

/* Two-column text layout — negative (yellow) left, positive (cyan) right */
.fw-divrange-moves {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--spacing-2) var(--spacing-4);
  margin: var(--spacing-3) 0;
}
.fw-divrange-col {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-2);
}
.fw-divrange-move {
  padding: var(--spacing-2) var(--spacing-3);
  border-left: 3px solid transparent;
  border-radius: 0 2px 2px 0;
}
.fw-divrange-move--neg {
  border-left-color: var(--pink);
  background: linear-gradient(to right,
    color-mix(in srgb, var(--pink) 30%, transparent),
    color-mix(in srgb, var(--pink)  5%, transparent));
}
.fw-divrange-move--pos {
  border-left-color: var(--green);
  background: linear-gradient(to right,
    color-mix(in srgb, var(--green) 30%, transparent),
    color-mix(in srgb, var(--green)  5%, transparent));
}
.fw-divrange-move-label {
  display: block;
  font-size: var(--t-body-sm);
  color: var(--report-ink);
  line-height: 1.4;
}
.fw-divrange-move-val {
  display: block;
  font-size: var(--chart-val-size);
  font-weight: var(--chart-val-wt);
  color: var(--chart-val-color);
  margin-top: 2px;
}
@container report-panel (max-width: 480px) {
  .fw-divrange-moves { grid-template-columns: 1fr; }
}

.fw-divrange-prose { margin-top: var(--spacing-3); }

.fw-divrange-item--chart { /* left border removed */ }
@media print {
  .fw-divrange-item--chart { break-inside: avoid; }
}

.fw-divrange-divider {
  border: none;
  border-top: 1px solid var(--report-border);
  margin: var(--spacing-5) 0;
}

/* ── fw-dbar: zero-centred diverging horizontal bar chart ──────────────────
   Grid: [neg-half 1fr] [axis 2px] [pos-half 1fr]
   Positive bars: "Label (£val)" right-aligned in neg-half; bar in pos-half.
   Negative bars: bar in neg-half; "Label (£val)" left-aligned in pos-half.
   Axis ticks (7) and baseline span all 3 columns via grid-column: 1 / -1. */

.fw-dbar-wrap {
  display: grid;
  grid-template-columns: 1fr 2px 1fr;
  row-gap: 4px;
  align-items: center;
  margin: var(--spacing-3) 0;
  padding-bottom: 30px;
}

/* Axis tick header */
.fw-dbar-ticks {
  grid-column: 1 / -1;
  display: flex;
  justify-content: space-between;
  padding-bottom: var(--spacing-2);
  border-bottom: 1px solid var(--chart-gridline);
  margin-bottom: var(--spacing-1);
}
.fw-dbar-tick {
  font-size: 10px;
  font-weight: 400;
  color: var(--report-ink-60);
  white-space: nowrap;
}
.fw-dbar-tick--zero {
  font-weight: 500;
  color: var(--report-ink);
}

/* Bar rows */
.fw-dbar-row { display: contents; }

.fw-dbar-label {
  font-size: 12px;
  font-weight: 300;
  color: var(--report-ink);
  line-height: 1.4;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.fw-dbar-row--total .fw-dbar-label { font-weight: 500; }
.fw-dbar-row--total > .fw-dbar-neg,
.fw-dbar-row--total > .fw-dbar-axis,
.fw-dbar-row--total > .fw-dbar-pos { padding-top: 20px; }

.fw-dbar-neg {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 8px;
}
.fw-dbar-pos {
  display: flex;
  justify-content: flex-start;
  align-items: center;
  gap: 8px;
}
.fw-dbar-axis {
  width: 0;
}
.fw-dbar-bar {
  height: 30px;
  border-radius: 2px;
  flex-shrink: 0;
}
.fw-dbar-row--total .fw-dbar-bar { height: 30px; }

.fw-dbar-bar--pos {
  background: linear-gradient(to right,
    color-mix(in srgb, var(--green) 10%, white),
    color-mix(in srgb, var(--green) 70%, white));
}
.fw-dbar-bar--neg {
  background: linear-gradient(to left,
    color-mix(in srgb, var(--band-developing) 10%, white),
    color-mix(in srgb, var(--band-developing) 70%, white));
}
.fw-dbar-bar--pos.fw-dbar-bar--total {
  background: linear-gradient(to right,
    color-mix(in srgb, var(--green) 10%, white),
    color-mix(in srgb, var(--green) 70%, white));
}
.fw-dbar-bar--neg.fw-dbar-bar--total {
  background: linear-gradient(to left,
    color-mix(in srgb, var(--band-developing) 10%, white),
    color-mix(in srgb, var(--band-developing) 70%, white));
}

/* Baseline rule */
.fw-dbar-baseline { display: none; }

@media print {
  .fw-dbar-wrap { break-inside: avoid; }
}
@container report-panel (max-width: 480px) {
  .fw-dbar-label { font-size: 10px; }
  .fw-dbar-tick  { font-size: 9px; }
}

/* ── fw-decision-tree ─────────────────────────────────────────────────────── */
.fw-dt-wrap {
  display: flex;
  align-items: center;
  gap: 0;
  margin: var(--spacing-5) 0 var(--spacing-6);
}
.fw-dt-root-cell {
  display: flex;
  align-items: center;
  flex-shrink: 0;
}
.fw-dt-root {
  border: 1.5px solid var(--report-border);
  border-radius: 8px;
  padding: 14px 18px;
  font-size: 14px;
  font-weight: 600;
  color: var(--navy);
  max-width: 160px;
  text-align: center;
  line-height: 1.4;
  overflow-wrap: break-word;
}
.fw-dt-hline {
  width: 32px;
  height: 2px;
  background: var(--report-border);
  flex-shrink: 0;
}
.fw-dt-branches {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.fw-dt-branch {
  display: flex;
  align-items: center;
  position: relative;
}
.fw-dt-branch::before {
  content: '';
  display: block;
  width: 28px;
  height: 2px;
  background: var(--report-border);
  flex-shrink: 0;
  position: relative;
  z-index: 1;
}
.fw-dt-branch::after {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 2px;
  background: var(--report-border);
}
.fw-dt-branch:first-child::after {
  top: 50%;
}
.fw-dt-branch:last-child::after {
  bottom: 50%;
}
.fw-dt-branch:only-child::after {
  display: none;
}
.fw-dt-option {
  flex: 1;
  min-width: 0;
  font-size: var(--t-body);
  font-weight: 300;
  color: var(--report-ink);
  line-height: 1.5;
  padding: 10px 14px;
  border-radius: 6px;
  border: 1px solid var(--report-border);
  overflow-wrap: break-word;
}
.fw-dt-branch--hl .fw-dt-option {
  font-weight: 500;
  color: var(--navy);
  border-color: var(--cyan);
  background: color-mix(in srgb, var(--cyan) 5%, white);
}
.fw-dt-opt-label {
  font-weight: 700;
  color: var(--navy);
  margin-right: 2px;
}
.fw-dt-branch--hl .fw-dt-opt-label {
  color: var(--cyan);
}
.fw-dt-pref-pill {
  display: inline-block;
  font-size: 11px;
  font-weight: 600;
  color: var(--cyan);
  background: color-mix(in srgb, var(--cyan) 10%, white);
  border: 1px solid color-mix(in srgb, var(--cyan) 30%, white);
  border-radius: 20px;
  padding: 2px 10px;
  margin-right: 6px;
  white-space: nowrap;
  vertical-align: middle;
}
.fw-dt-meta {
  border-top: 1px solid var(--report-border);
  padding-top: var(--spacing-5);
  margin-top: var(--spacing-2);
}
@media (max-width: 767px) {
  .fw-dt-wrap { flex-direction: column; align-items: stretch; }
  .fw-dt-root-cell { flex-direction: column; align-items: flex-start; }
  .fw-dt-root { max-width: 100%; text-align: left; }
  .fw-dt-hline { width: 2px; height: 20px; }
  .fw-dt-branch::before { display: none; }
  .fw-dt-branch::after { display: none; }
}

/* Mobile: stack negative above positive; hide axis (label/value text suffices) */
@container report-panel (max-width: 600px) {
  .fw-divrange-chart { flex-direction: column; gap: var(--spacing-3); }
  .fw-divrange-spine { width: 100%; height: 1px; align-self: auto; margin: 0; }
  .fw-divrange-half { width: 100%; }
  .fw-divrange-half--neg .fw-divrange-row { flex-direction: row; }
  .fw-divrange-half--neg .fw-divrange-meta { text-align: left; }
  .fw-divrange-meta { width: 100%; }
  .fw-divrange-axis { display: none; }
}


/* ═══════════════════════════════════════════════════════════════════════════
   C3b — LINE TREND CHART (SVG-based)
   Quantitative values over time. Max 4 series.
   ═══════════════════════════════════════════════════════════════════════════ */

.mi-line-trend {
  /* Full width. The viewBox width is set to the 800px content column (see the
     partial's W default), so at full width the SVG renders ~1:1 — dots (r=7.5)
     show at a true 15px and labels (11px) at a true 11px, no upscaling. */
  width: 100%;
  overflow: visible;
  display: block;
}

.mi-line-grid {
  stroke: var(--chart-gridline); /* was var(--report-border) — unified gridline token */
  stroke-width: 0.5;
  stroke-dasharray: 4 4;
}

.mi-line-axis {
  stroke: var(--chart-gridline); /* was var(--report-border) — unified gridline token */
  stroke-width: 1;
}

.mi-line-series {
  fill: none;
  stroke: var(--report-ink);
  stroke-width: 2;
}

/* Colour is driven per-series by inline style in line-trend.html (palette
   indexed by series position: index 0 = --cyan, then kicker tokens).
   These class rules govern stroke-weight only: hl (primary) series is 3px,
   dim (secondary) series 2px so the primary line reads as dominant.
   CSS stroke/fill values are fallbacks for any edge case without inline style.
   Christine, 26 June 2026. Was: all hl→cyan 3px, all dim→green 3px. */
.mi-line-series.hl  { stroke: var(--cyan);  stroke-width: 3; }
.mi-line-series.dim { stroke: var(--green); stroke-width: 2; }

.mi-line-dot    { fill: var(--green); stroke: none; }
.mi-line-dot.hl { fill: var(--cyan);  stroke: none; }

/* SL — slope-chart rank colour now pulls from the canonical kicker range IN
   SEQUENCE (rank N → --kickerNN), applied INLINE in slope-chart.html on each
   slope line + both of its dots. That keeps the colour data-driven and covers
   all 16 ranks (was a cherry-picked 3-entry map kicker02/05/10 here, only top
   3 ranks coloured). Christine, 1 June 2026. */

.mi-line-txt {
  font-size: 11px;
  fill: var(--report-ink);
  font-family: inherit;
}

.mi-line-end {
  font-size: 11px;
  font-weight: var(--chart-name-wt);
  fill: var(--chart-name-color);
  font-family: inherit;
}

.mi-line-end.hl { fill: var(--cyan); font-weight: var(--chart-name-hl-wt); }   /* primary series label tracks the cyan primary line. Christine, 1 June 2026 */

/* Single-series legend row — swatch + name rendered below the SVG when a
   line-trend chart has exactly one series. Replaces the in-plot end label
   that was suppressed for single-series (27 Jun 2026). */
.mi-line-legend {
  display: flex;
  align-items: center;
  gap: var(--spacing-2);
  margin-top: var(--spacing-2);
}
.mi-line-legend-swatch {
  width: 20px;
  height: 3px;
  border-radius: 2px;
  flex-shrink: 0;
}
.mi-line-legend-label {
  font-size: var(--chart-name-size);
  font-weight: var(--chart-name-wt);
  color: var(--chart-name-color);
  font-family: inherit;
}

/* Bubble-matrix uses a narrower viewBox (W=640) than the line/slope charts
   (W=800), so its in-SVG text scales UP ~1.25× on screen — the 11px axis labels
   rendered noticeably larger than every other chart. Counter-scale so they match
   an 11px label in an 800-wide viewBox: 11 × 640/800 = 8.8px. Scoped to
   bubble-matrix (.cl-matrix-wrap with a direct <svg> child). (Christine, 31 May 2026.) */
.cl-matrix-wrap:has(> svg) .mi-line-txt { font-size: 8.8px; /* ≈ 11px on screen */ }
/* The user's bubble label is no longer SVG <text>; it's an HTML overlay
   (.bm-dot-label, fixed 11px) so it stays consistent with the positioning label
   at any width. (Christine, 31 May 2026.)
   Was: .cl-matrix-wrap:has(> svg) .mi-line-end { font-size: 8.8px; } */

/* Bubble-matrix bubbles: lighter, outlined treatment so a plot full of bubbles no
   longer reads as heavy solid blobs — a 3px coloured ring with a faint 10% tint of
   the same colour (the tint lets overlapping bubbles show through). The per-bubble
   colour comes in via the inline --bm-c custom prop. The user's (.hl) bubble keeps
   a solid fill so the single "you" point still pops. (Christine, 31 May 2026.
   Was: every bubble a solid fill, opacity 1.) */
.bm-bubble {
  fill: color-mix(in srgb, var(--bm-c) 10%, transparent);
  stroke: var(--bm-c);
  stroke-width: 1.2; /* ≈ 1.5px on screen after the 640→~800 viewBox upscale (was 0.8 ≈ 1px) */
}
.bm-bubble.hl {
  fill: var(--bm-c);
  stroke: none;
}

/* SL — current-column name labels are flat black (see .mi-slope text below) for
   readability; rank colour lives on the dots + lines only. The old
   .mi-line-end--rank-* band-colour rules were dead (.mi-slope text overrode
   them) and are removed. Christine, 1 June 2026. */

/* Slope labels match the canonical chart-label style — flat black, 11px,
   300 weight — regardless of rank. Rank colour now lives only on the slope
   dots + lines. Scoped to .mi-slope so line-trend text is untouched. */
.mi-slope text { fill: var(--report-ink); font-size: 11px; font-weight: 300; }


/* ═══════════════════════════════════════════════════════════════════════════
   C4 — HORIZONTAL BAR
   Rankings of 3–10 items. One .hl bar only.
   ═══════════════════════════════════════════════════════════════════════════ */

.mi-hbar-chart {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-4);   /* row gap widened to 16px for clearer separation between two-line rows */
  margin-bottom: 30px;
}

.mi-hbar-row {
  display: grid;
  /* Three columns: name (with its descriptor stacked beneath) · bar track ·
     score. The descriptor lives under the vendor name so the score column
     stays short and nothing overflows; rows grow to ~2 lines tall. */
  grid-template-columns: var(--chart-label-col) minmax(0, 2fr) auto;
  align-items: center;
  gap: var(--spacing-3);
}

/* C4 — name + value columns size to CONTENT so the bar flexes to fill the
   middle, instead of the fixed 350px (--chart-label-col) label column that
   left a big white gap when company names are short (Christine, 1 June 2026.
   Was: per-row grid with a fixed label column). The whole chart becomes ONE
   3-col grid and the rows go display:contents, so the shared max-content label
   column keeps every bar's left edge aligned across rows. Scoped to C4 via the
   .mi-hbar-c4 modifier (set in horizontal-bar.html); the C6 group variant
   (grouped-horizontal.html, rows nested in .mi-hbar-group) has no such class
   and is untouched. Mobile reverts to the per-row grid below (@media). */
.mi-hbar-c4 {
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr) max-content;
  column-gap: var(--spacing-3);
  row-gap: var(--spacing-4);
  align-items: center;
}
.mi-hbar-c4 > .mi-hbar-row { display: contents; }

.mi-hbar-legend {
  display: flex;
  gap: var(--spacing-4);
  margin-bottom: var(--spacing-3);
}

.mi-hbar-legend-item {
  display: flex;
  align-items: center;
  gap: var(--spacing-2);
  font-size: 14px;
  color: var(--report-ink);
}

.mi-hbar-legend-swatch {
  width: 16px;
  height: 6px;
  display: inline-block;
  border-radius: 2px;
}

/* LOCKED — Christine 2026-05-27. Value-role palette:
   series-a (Current) → --cyan, series-b (Target) → --gray-light.
   Swatches and bar fills share the same two tokens so the legend
   reads true to the chart. Do NOT recolour without her sign-off. */
.mi-hbar-legend-swatch--dim { background: var(--cyan); }
.mi-hbar-legend-swatch--hl  { background: var(--gray-light); }

.mi-hbar-group {
  margin-bottom: var(--spacing-4);
}

/* C6 hoists the row label to .mi-hbar-group above; rows only need track + value.
   Drops the empty 200px label column so C6 track width matches C4. */
.mi-hbar-group .mi-hbar-row { grid-template-columns: 1fr; }

/* Vertical breathing room for the two stacked Current/Target rows inside a
   C6 group. The bar fill text label (.mi-hbar-secondary) is absolutely
   positioned inside the 14px track and overflows it vertically (~2-3px each
   side), so consecutive rows need ≥6px between them to keep the label off
   the next row's track. The first row in the group sits flush against the
   group label which already has its own margin-bottom. */
.mi-hbar-group .mi-hbar-row + .mi-hbar-row {
  margin-top: 8px;
}

.mi-hbar-row--compare {
  margin-top: 4px;
}

.mi-hbar-label {
  font-size: var(--chart-name-size);
  font-weight: var(--chart-name-wt);
  color: var(--chart-name-color);
  line-height: var(--t-heading-lh);
  text-align: left;
  margin-bottom: var(--spacing-2);
}

.mi-hbar-label.hl {
  font-weight: var(--chart-name-hl-wt);
  color: var(--chart-name-hl-color);
}

.mi-hbar-track {
  position: relative;
  height: 14px;   /* matches C1 .mi-seg-bar */
  overflow: hidden;
}

.mi-hbar-fill {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  border-radius: var(--radius-sm);
  background: var(--report-white);
  border: 1px solid var(--report-border);
}

/* C4 single-series horizontal bar palette. Highlighted rows stay cyan; the
   non-highlighted (.dim) rows are a neutral grey so the cyan reads as the
   hero. Christine 2026-05-29.
   (C6 grouped overrides below stay LOCKED on cyan/gray-light.) */
.mi-hbar-fill.hl  { background: var(--cyan); border: none; }
.mi-hbar-fill.dim { background: var(--gray-light); border: none; }

/* C6 — Grouped horizontal (paired comparison, e.g. year-on-year).
   Scoped to .mi-hbar-group so C4 (which has no group wrapper) is unaffected.
   Convention: .dim = series-a (mint, last year), .hl = series-b (blue, current year). */
/* LOCKED — matches legend swatches above. Do NOT recolour. */
.mi-hbar-group .mi-hbar-fill.dim { background: var(--cyan); }
.mi-hbar-group .mi-hbar-fill.hl  { background: var(--gray-light); }

/* OMR value-delivery throughput chart (Plan vs Actual) — the "Actual" series
   (series-b, rendered .hl) is green so it reads as the real/delivered number,
   not the shared LOCKED gray-light. Scoped to this chart only; every other
   consumer of grouped-horizontal.html keeps the default cyan/gray-light
   palette above. Christine, 4 July 2026.
   Gradient fill on both series matches the adb-bar-- (assessment-dimension-
   bars) visual language — light-to-full colour-mix — per Christine's
   design-QA note that OMR bars should read like the platform's "properly
   formatted" gradient bars, not the shared C6 flat fill. */
.fw-omr-throughput-chart .mi-hbar-fill.dim { background: linear-gradient(to right, color-mix(in srgb, var(--cyan)  3%, var(--report-white)), var(--cyan)); }
.fw-omr-throughput-chart .mi-hbar-fill.hl  { background: linear-gradient(to right, color-mix(in srgb, var(--green) 3%, var(--report-white)), var(--green)); }
.fw-omr-throughput-chart .mi-hbar-legend-swatch--hl { background: var(--green); }

/* C4 opt-in 5-tier score banding (Christine, 6 Jul 2026): some C4 consumers
   (problem-analysis "What It's Costing") plot a SEVERITY VALUE, not a
   "biggest vs the rest" comparison — every row can legitimately be High, so
   the hl/dim cyan/grey scheme above painted every bar identically cyan and
   made "High" look like a computed winner rather than a rating. band_scale
   in the figure data opts a chart into the same 5-colour percentage bands
   used on assessment score bars (purple→pink→yellow→cyan→green, 0–29/30–49/
   50–69/70–89/90–100%), so severity reads as a rating scale instead of a
   ranking. Scoped to .mi-hbar-fill.band-* so non-opted-in charts (the
   default hl/dim scheme, C6 grouped, OMR throughput) are unaffected. */
/* Light-to-full colour-mix gradient (10%→100%) — same recipe as the
   adb-bar-- assessment-dimension-bars and the OMR throughput chart, so
   these severity bars read as the platform's standard gradient bar
   language rather than a flat fill. Christine, 6 Jul 2026. */
.mi-hbar-fill.band-emerging   { background: linear-gradient(to right, color-mix(in srgb, var(--band-emerging)   10%, var(--report-white)), var(--band-emerging));   border: none; }
.mi-hbar-fill.band-developing { background: linear-gradient(to right, color-mix(in srgb, var(--band-developing) 10%, var(--report-white)), var(--band-developing)); border: none; }
.mi-hbar-fill.band-solid      { background: linear-gradient(to right, color-mix(in srgb, var(--band-solid)      10%, var(--report-white)), var(--band-solid));      border: none; }
.mi-hbar-fill.band-strong     { background: linear-gradient(to right, color-mix(in srgb, var(--band-strong)     10%, var(--report-white)), var(--band-strong));     border: none; }
.mi-hbar-fill.band-excellent  { background: linear-gradient(to right, color-mix(in srgb, var(--band-excellent)  10%, var(--report-white)), var(--band-excellent));  border: none; }

.mi-hbar-fill.stripe {
  background-image: repeating-linear-gradient(45deg, var(--report-ink-35) 0, var(--report-ink-35) 1px, var(--report-white) 0, var(--report-white) 50%);
  background-size: 6px 6px;
  background-color: var(--report-white);
  border: 0.5px solid var(--report-border);
}

.mi-hbar-inner-val {
  position: absolute;
  left: var(--spacing-2);
  top: 50%;
  transform: translateY(-50%);
  font-size: var(--chart-val-size);
  font-weight: var(--chart-val-wt);
  color: var(--chart-val-color);
  white-space: nowrap;
}

.mi-hbar-inner-val.hl  { color: var(--report-white); font-weight: var(--chart-val-hl-wt); }
.mi-hbar-inner-val.dim { color: var(--chart-val-color); font-weight: var(--chart-val-wt); }

/* C6 grouped-horizontal keeps the historical pattern: secondary lives INSIDE
   .mi-hbar-track and is absolutely positioned at left:<pct>% (placed by inline
   style in the template). Scoped via :not(:has(.mi-hbar-secondary)) on the
   track so we only apply absolute styling when the track actually contains
   the secondary (C6 case), keeping C4 — where the secondary is a row sibling
   — free to flow in its own grid column. */
.mi-hbar-track > .mi-hbar-secondary {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  white-space: nowrap;
}

/* C4 inline value — sits immediately to the right of each bar's fill end
   (left:<pct>% set inline by the template) with a small padding so it
   doesn't kiss the bar. ── */
.mi-hbar-track > .mi-hbar-secondary--inline { padding-left: 8px; }

.mi-hbar-secondary    {
  font-size: var(--chart-name-size);
  font-weight: var(--chart-name-wt);
  color: var(--chart-name-color);
  padding-left: 6px;
  /* C4 default: secondary is a row sibling in the 3rd grid column (160px
     wide, see .mi-hbar-row), flowing in normal layout — so text wraps to a
     2nd line ONLY when it doesn't fit, and the row grows to fit wrapped
     text so it never overlaps adjacent rows. */
  white-space: normal;
  line-height: 1.25;
}
.mi-hbar-secondary.hl { font-weight: var(--chart-val-hl-wt); color: var(--chart-val-hl-color); }

/* C4 name cell: vendor name with its descriptor inline in brackets. The
   descriptor moved out of the score column so long text wraps under the name
   instead of overflowing past the bar. */
/* Only the leader (.hl) is bold; the rest drop to 300 (base) so weight alone
   marks the leader. Christine, 1 June 2026. Was: both medium (500). */
.mi-hbar-namecell .mi-hbar-label { margin-bottom: 0; font-weight: var(--chart-name-wt); }
.mi-hbar-namecell .mi-hbar-label.hl { font-weight: var(--chart-name-hl-wt); }
.mi-hbar-sub {
  font-size: var(--t-small);
  font-weight: var(--font-weight-light);
  color: var(--report-ink);
}


/* ── STACKED COLUMN ────────────────────────────────────────────────────────
   Per-column hue (cascades to segments via custom properties).
   Per-segment role: solid (full hue), pill (translucent hue), empty (white).
   Production template auto-cycles hues + roles by index — no data contract change. */
.mi-stacked {
  display: flex;
  gap: var(--spacing-4);
  align-items: flex-end;
  margin-bottom: var(--spacing-3);
}
.mi-stacked-col {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0;
}
.mi-stacked-bar {
  width: 100%;
  height: 200px;
  display: flex;
  flex-direction: column-reverse;   /* segment 0 renders at bottom */
  border: 1px solid var(--report-border);
  border-radius: var(--radius-sm);
  overflow: hidden;
}
.mi-stacked-label {
  font-size: 14px;
  color: var(--report-ink);
  margin-top: var(--spacing-2);
  text-align: center;
}

/* Per-series colour — a single cyan ramp (full → 50% → 20% tint toward white)
   so the stack reads as one family instead of three competing blocks.
   s0/s1/s2 = New business / Renewals / Upsell. */
.mi-stacked-seg            { width: 100%; flex-shrink: 0; }
.mi-stacked-seg--s0        { background: var(--cyan); }
.mi-stacked-seg--s1        { background: color-mix(in srgb, var(--cyan) 40%, var(--report-white)); }
.mi-stacked-seg--s2        { background: color-mix(in srgb, var(--cyan) 20%, var(--report-white)); }

/* Legend swatches mirror the per-series colours */
.mi-stacked-legend         { display: flex; gap: var(--spacing-4); flex-wrap: wrap; margin-top: var(--spacing-2); }
.mi-stacked-legend-item    { display: flex; align-items: center; gap: var(--spacing-2); font-size: 14px; color: var(--report-ink); }
.mi-stacked-legend-swatch  { width: 16px; height: 10px; display: inline-block; border-radius: 2px; }
.mi-stacked-legend-swatch--s0 { background: var(--cyan); }
.mi-stacked-legend-swatch--s1 { background: color-mix(in srgb, var(--cyan) 40%, var(--report-white)); }
.mi-stacked-legend-swatch--s2 { background: color-mix(in srgb, var(--cyan) 20%, var(--report-white)); }


/* ═══════════════════════════════════════════════════════════════════════════
   C5 — TWO-BAR + MULTIPLIER
   Exactly 2 groups. Always include the multiplier callout.
   ═══════════════════════════════════════════════════════════════════════════ */

.mi-twobar-chart {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-2);   /* match .mi-hbar-chart rhythm (was spacing-4 / 16px) */
  margin-bottom: 30px;
}

.mi-twobar-row {
  display: grid;
  /* Matches .mi-hbar-row exactly (same columns + gap) so the two
     charts' bar tracks line up 1:1 — label / track / value. The
     multiplier (e.g. 3.4×) now lives inline inside the label, so a
     large multiplier can never widen the layout or shift the track. */
  grid-template-columns: var(--chart-label-col) minmax(0, 2fr) auto;
  gap: var(--spacing-3);
  align-items: center;
}

.mi-twobar-label    { font-size: var(--chart-name-size); font-weight: var(--chart-name-wt); color: var(--chart-name-color); text-align: left; }
.mi-twobar-label.hl { font-weight: var(--chart-name-hl-wt); color: var(--chart-name-hl-color); }

.mi-twobar-track {
  position: relative;
  height: 14px;   /* matches C1/C4 */
}

/* Value-driven palette per Christine: HIGHER bar reads cyan (--cyan):
   28% tint on non-hl rows, solid on the hl row to preserve the
   call-out. LOWER bar reads neutral gray (--gray-light, matching the
   C4/C6 secondary-series convention) so it recedes as the baseline
   value. Master tokens only — the shared band-* tokens are
   deliberately NOT touched (they drive every other chart). */
.mi-twobar-fill            { position: absolute; top: 0; left: 0; height: 100%; border-radius: var(--radius-sm); border: none; background: var(--cyan); }
.mi-twobar-fill.is-lower   { background: var(--gray-light); }
.mi-twobar-fill.is-higher  { background: var(--cyan); }
.mi-twobar-fill.is-higher.hl { background: var(--cyan);  }

.mi-twobar-value    { font-size: var(--chart-val-size); font-weight: var(--chart-val-wt); color: var(--chart-val-color); white-space: nowrap; text-align: right; }
.mi-twobar-value.hl { font-weight: var(--chart-val-hl-wt); color: var(--chart-val-hl-color); }

.mi-twobar-multiplier { font-size: var(--chart-val-size); font-weight: var(--chart-val-wt); color: var(--chart-val-color); white-space: nowrap; text-align: center; }

.mi-twobar-note {
  font-size: var(--t-small);
  font-weight: var(--font-weight-light);
  line-height: 1.7;
  color: var(--report-ink-60);
  margin-top: 8px;
  margin-bottom: var(--spacing-6);
}


/* ═══════════════════════════════════════════════════════════════════════════
   C7 — DOT PLOT
   8+ items on shared axis. Geographic spread, salary ranges, entity positions.
   ═══════════════════════════════════════════════════════════════════════════ */

.mi-dot-chart {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-5);
}

.mi-dot-row {
  display: grid;
  /* label · track · value(legend). Both side columns are sized to fit
     2-line wraps of typical labels (e.g. "Originator biologics (Roche,
     MSD)" on the left, "25–40% below originator" on the right) without
     truncation. The track stays flexible (1fr) and is the dominant
     visual element. */
  grid-template-columns: 170px 1fr 180px;
  gap: var(--spacing-4);
  align-items: center;
}

/* Label & value share the same compact size so the two metadata columns
   read as a matched pair instead of competing visual weights. */
.mi-dot-label    { font-size: var(--t-small); font-weight: var(--chart-name-wt); color: var(--chart-name-color); text-align: right; line-height: 1.3; }
.mi-dot-label.hl { font-weight: var(--chart-name-hl-wt); color: var(--chart-name-hl-color); }

.mi-dot-track {
  position: relative;
  height: 28px;
  /* was overflow: hidden — clipped the dot circle when a row's value sat
     at/near the 0% or 100% edge of the scale (circle is centered on its
     position via translate(-50%), so half the circle fell outside the
     track and got cropped). Connector bars and the point position are
     already clamped to 0-100% in the template, so nothing here actually
     needs clipping. */
  overflow: visible;
}

.mi-dot-axis-line {
  position: absolute;
  top: 50%;
  left: 0;
  right: 0;
  height: 0;
  border-top: 1px dashed var(--chart-gridline); /* was var(--report-border) — unified gridline token */
  transform: translateY(-50%);
}

.mi-dot-connector {
  position: absolute;
  top: 50%;
  left: 0;
  height: 2px;
  background: var(--gray-mid);
  opacity: 1;
  border-radius: var(--radius-sm);
  transform: translateY(-50%);
}

/* C7 default (single-series dot plot) → mint */
.mi-dot-connector.hl { height: 3px; background: var(--band-strong); opacity: 1; }

/* C8 (dual-series) → coral, scoped via .mi-dot-chart--dual modifier */
.mi-dot-chart--dual .mi-dot-connector.hl { background: var(--band-developing); }

/* Husqvarna working-capital dot plot (report 604, Christine, 1 June 2026):
   colour each connector line by ROW POSITION — top row cyan, then kicker06
   through kicker16 sequentially down the rows. Scoped to this one report's
   single-series classic dot plot (excludes the tier/dual variants), so every
   other report's dot plot keeps its neutral one-outlier encoding. Uses
   .mi-dot-row:nth-child() (no :has/subgrid) so it is PDF/Firecrawl safe. */
.report-paginated[data-report-id="604"] .mi-dot-chart:not(.mi-dot-chart--tier):not(.mi-dot-chart--dual) .mi-dot-row:nth-child(1)  .mi-dot-connector { background: var(--cyan); }
.report-paginated[data-report-id="604"] .mi-dot-chart:not(.mi-dot-chart--tier):not(.mi-dot-chart--dual) .mi-dot-row:nth-child(2)  .mi-dot-connector { background: var(--kicker06); }
.report-paginated[data-report-id="604"] .mi-dot-chart:not(.mi-dot-chart--tier):not(.mi-dot-chart--dual) .mi-dot-row:nth-child(3)  .mi-dot-connector { background: var(--kicker07); }
.report-paginated[data-report-id="604"] .mi-dot-chart:not(.mi-dot-chart--tier):not(.mi-dot-chart--dual) .mi-dot-row:nth-child(4)  .mi-dot-connector { background: var(--kicker08); }
.report-paginated[data-report-id="604"] .mi-dot-chart:not(.mi-dot-chart--tier):not(.mi-dot-chart--dual) .mi-dot-row:nth-child(5)  .mi-dot-connector { background: var(--kicker09); }
.report-paginated[data-report-id="604"] .mi-dot-chart:not(.mi-dot-chart--tier):not(.mi-dot-chart--dual) .mi-dot-row:nth-child(6)  .mi-dot-connector { background: var(--kicker10); }
.report-paginated[data-report-id="604"] .mi-dot-chart:not(.mi-dot-chart--tier):not(.mi-dot-chart--dual) .mi-dot-row:nth-child(7)  .mi-dot-connector { background: var(--kicker11); }
.report-paginated[data-report-id="604"] .mi-dot-chart:not(.mi-dot-chart--tier):not(.mi-dot-chart--dual) .mi-dot-row:nth-child(8)  .mi-dot-connector { background: var(--kicker12); }
.report-paginated[data-report-id="604"] .mi-dot-chart:not(.mi-dot-chart--tier):not(.mi-dot-chart--dual) .mi-dot-row:nth-child(9)  .mi-dot-connector { background: var(--kicker13); }
.report-paginated[data-report-id="604"] .mi-dot-chart:not(.mi-dot-chart--tier):not(.mi-dot-chart--dual) .mi-dot-row:nth-child(10) .mi-dot-connector { background: var(--kicker14); }
.report-paginated[data-report-id="604"] .mi-dot-chart:not(.mi-dot-chart--tier):not(.mi-dot-chart--dual) .mi-dot-row:nth-child(11) .mi-dot-connector { background: var(--kicker15); }
.report-paginated[data-report-id="604"] .mi-dot-chart:not(.mi-dot-chart--tier):not(.mi-dot-chart--dual) .mi-dot-row:nth-child(12) .mi-dot-connector { background: var(--kicker16); }

/* Generic C7 legend — opt-in via fd.legend (list of {swatch:'dot'|'line', label}).
   Explains the chart grammar (what a dot vs. a line segment means) without
   assuming per-row colour meaning, so it works whether rows share one colour
   or each gets its own (--kickerNN) palette entry. */
.mi-dot-legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--spacing-4);
  margin-bottom: var(--spacing-3);
}
.mi-dot-legend__item {
  display: flex;
  align-items: center;
  gap: var(--spacing-2);
  font-size: var(--t-small);
  color: var(--report-ink);
}
.mi-dot-legend__swatch--dot {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: var(--radius-full);
  /* Matches .mi-dot-circle.hl (the "Our anchor" / highlighted row dot) so
     the legend swatch never shows a different colour than the dot it's
     explaining — was hardcoded gray while the actual dot uses
     --band-strong (cyan), a mismatch users would notice immediately. */
  background: var(--band-strong);
}
.mi-dot-legend__swatch--line {
  display: inline-block;
  width: 18px;
  height: 2px;
  border-radius: var(--radius-sm);
  background: var(--gray-mid);
}

.mi-dot-circle {
  position: absolute;
  top: 50%;
  width: 10px;
  height: 10px;
  border-radius: var(--radius-full);
  background: var(--gray-mid);
  border: none;
  transform: translate(-50%, -50%);
}

.mi-dot-circle.hl {
  width: 15px;
  height: 15px;
  background: var(--band-strong);   /* C7 mint */
  border: none;
}

.mi-dot-chart--dual .mi-dot-circle.hl { background: var(--band-developing); }   /* C8 coral (legacy, unused) */

/* C8 dual-series: colour the SERIES, not the row, so the reader can always
   tell the two apart on every row. Benchmark (industry avg) = brand purple
   (--purple); "you" = cyan. Dots share the 10px base (matches slope-chart/
   line-trend r=5). The 3px connector is the gap between the two scores and
   gradients from the lower dot's colour (left) to the higher dot's (right):
   --up = "you" at/above avg (purple->cyan); --down = "you" below (cyan->
   purple). Plain --gray-light stays as a fallback if no direction class. */
/* C8 dot/connector enlarged (dots 10→14px, connector 3→4px) so the series
   read at the same weight as the other charts (per Christine, 31 May 2026).
   Scoped to --dual; single-series C7 and tier variants are unchanged. */
.mi-dot-chart--dual .mi-dot-circle { width: 14px; height: 14px; }
.mi-dot-chart--dual .mi-dot-connector { height: 4px; background: var(--gray-light); }
.mi-dot-chart--dual .mi-dot-connector--up { background: linear-gradient(to right, var(--purple), var(--cyan)); }
.mi-dot-chart--dual .mi-dot-connector--down { background: linear-gradient(to right, var(--cyan), var(--purple)); }
.mi-dot-chart--dual .mi-dot-circle--a { background: var(--purple); }
.mi-dot-chart--dual .mi-dot-circle--b { background: var(--cyan); }

/* C8 legend — tokenised (keeps px/hex out of the template). Swatches mirror
   the plotted dots: benchmark = brand purple (--purple) 14px, you = cyan 14px. */
.mi-dual-legend {
  display: flex;
  gap: var(--spacing-4);
  margin-bottom: var(--spacing-3);
}
.mi-dual-legend__item {
  display: flex;
  align-items: center;
  gap: var(--spacing-2);
  font-size: var(--t-small);
  color: var(--report-ink);
}
.mi-dual-legend__swatch {
  display: inline-block;
  border-radius: var(--radius-full);
}
.mi-dual-legend__swatch--a { width: 14px; height: 14px; background: var(--purple); }
.mi-dual-legend__swatch--b { width: 14px; height: 14px; background: var(--cyan); }

/* The end-column score is the user's figure (series B) — semibold so it reads
   as the takeaway, kept dark for legibility (cyan-on-white fails contrast). */
.mi-dot-chart--dual .mi-dot-value--you { font-weight: var(--font-weight-semibold); }

/* ── C7 TIER MODE ─────────────────────────────────────────────────────────
   Triggered when every row carries a `share` (% of items in that tier).
   The "where do they cluster" story becomes data-driven: dot size encodes
   share (largest tier = --rpt-dot-max), each tier gets its own palette
   colour, connectors are a uniform 3px, and no single row is highlighted —
   all tiers read as equal-weight. Christine 2026-05-31. Classic single-hl
   distribution dot-plots (no `share`) are untouched by everything below. */
.mi-dot-chart--tier .mi-dot-connector {
  height: 3px;
  background: var(--dot-color, var(--gray-mid));
}
.mi-dot-chart--tier .mi-dot-circle {
  background: var(--dot-color, var(--gray-mid));
}
/* Dot diameter interpolates between the min/max tokens by --dot-scale
   (0–1, = share ÷ largest share in the chart). Pure CSS calc so no px
   lives in the template. */
.mi-dot-circle--scaled {
  width:  calc(var(--rpt-dot-min) + (var(--rpt-dot-max) - var(--rpt-dot-min)) * var(--dot-scale, 0));
  height: calc(var(--rpt-dot-min) + (var(--rpt-dot-max) - var(--rpt-dot-min)) * var(--dot-scale, 0));
}
/* Tier mode: labels are flat/equal weight, EXCEPT the dominant tier (largest
   share), whose name goes bold — data-earned emphasis on the lead tier. */
.mi-dot-chart--tier .mi-dot-label {
  font-weight: var(--chart-name-wt);
  color: var(--chart-name-color);
}
.mi-dot-chart--tier .mi-dot-label--lead { font-weight: var(--chart-name-hl-wt); }
/* Muted share read-out under each tier's callout, so the size encoding is
   decodable rather than guessed. */
.mi-dot-share {
  display: block;
  font-size: var(--t-small);
  font-weight: var(--font-weight-light);
  color: var(--report-ink);
  line-height: 1.3;
  margin-top: var(--spacing-2xs);
}

/* Legacy inline callout (kept harmless in case any older report still
   references it via cached HTML — current template uses .mi-dot-value). */
.mi-dot-callout {
  position: absolute;
  bottom: calc(100% - 6px);
  font-size: var(--t-small);
  font-weight: var(--font-weight-medium);
  color: var(--report-ink);
  white-space: nowrap;
  left: 0 !important;
  width: 100%;
  text-align: center;
  transform: none;
}

/* New right-hand value cell — reads as a legend keyed to each row.
   Right-aligned so prices line up vertically and unequal callout
   widths never push dots around. */
.mi-dot-value {
  font-size: var(--t-small);
  font-weight: var(--font-weight-medium);
  color: var(--report-ink);
  text-align: left;
  /* Allow wrapping to a 2nd line instead of truncating with an ellipsis
     — the column is now wide enough that typical callouts fit, and the
     fallback is a clean wrap rather than hidden information. */
  white-space: normal;
  line-height: 1.3;
}
.mi-dot-value.hl { font-weight: var(--font-weight-semibold); color: var(--chart-name-hl-color); }

.mi-dot-axis-labels {
  display: grid;
  /* Mirror .mi-dot-row so ticks sit directly under the track and the
     scale_unit sits under the value column. */
  grid-template-columns: 170px 1fr 180px;
  gap: var(--spacing-4);
  margin-top: var(--spacing-2);
  align-items: baseline;
}

.mi-dot-axis-unit {
  font-size: var(--t-small);
  color: var(--report-ink);
  opacity: 0.7;
  text-align: right;
  display: block;
}

.mi-dot-axis-scale {
  display: flex;
  justify-content: space-between;
}

.mi-dot-axis-tick { font-size: var(--t-small); color: var(--report-ink); }


/* ═══════════════════════════════════════════════════════════════════════════
   T2 — SCORECARD TABLE
   Multiple entities rated across multiple dimensions.
   ═══════════════════════════════════════════════════════════════════════════ */

.scorecard {
  width: 100%;
  border-collapse: collapse;
}

.scorecard thead th {
  font-size: var(--t-heading);
  font-weight: var(--t-heading-wt);
  color: var(--t-heading-color);
  letter-spacing: 0.5px;
  padding: var(--spacing-2) var(--spacing-3);
  /* Header-row divider: gray-dark 1px, consistent with every component/table
     header row (Christine, 1 June 2026). Was: 1.5px var(--report-ink). */
  border-bottom: 1px solid var(--gray-dark);
  text-align: left;
}

.scorecard tbody td {
  font-size: 16px;
  font-weight: var(--font-weight-light);
  color: var(--report-ink);
  padding: var(--spacing-3) var(--spacing-3);
  border-bottom: 1px solid var(--report-border);
  vertical-align: top;
}

.scorecard tbody tr:last-child td { border-bottom: none; }

.scorecard tbody td:first-child {
  font-weight: 400;
  color: var(--report-ink);
}

/* Entity descriptor — replaces the old in-cell .badge pill. Sits under the
   entity name as a light caption so the dimension columns stay clean. */
.sc-entity-desc {
  margin-top: 2px;
  font-size: var(--t-small);
  font-weight: 400;
  font-style: italic;
  color: var(--chart-val-color);
}

/* Pip score dots */
.pip {
  display: flex;
  gap: 3px;
}

.pip span {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: var(--radius-full);
  background: var(--gray-light);
}

.pip span.on { background: var(--ink-2); }
.row-rising .pip span.on { background: var(--cyan); }

/* T2 — Mobile: card-per-row layout.
   Below 600px the scorecard table flattens — each <tr> becomes a
   stacked "card" with the entity name as a heading and every
   dimension shown as a labelled row (label left, pip/badge right).
   Relies on each <td> carrying data-label="<dimension>" (the entity
   cell uses an empty data-label so no label is rendered above it). */
@media (max-width: 600px) {
  .scorecard,
  .scorecard thead,
  .scorecard tbody,
  .scorecard tr,
  .scorecard td { display: block; width: 100%; }
  .scorecard thead { display: none; }
  .scorecard tbody tr {
    border-bottom: 1px solid var(--report-border);
    padding: 12px 0;
  }
  .scorecard tbody tr:last-child { border-bottom: none; }
  .scorecard tbody td {
    border-bottom: none;
    padding: 6px 0;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
  }
  /* Entity cell: full-width heading, no data-label prefix */
  .scorecard tbody td:first-child {
    display: block;
    font-size: 16px;
    font-weight: 500;
    padding-bottom: 8px;
  }
  .scorecard tbody td[data-label]:not(:first-child)::before {
    content: attr(data-label);
    font-size: 13px;
    font-weight: 400;
    color: var(--chart-val-color);
  }
}

/* T2 — sc-bar (replaces pips in new templates) */
.sc-bar {
  display: block;
  height: 34px;
  border-radius: var(--radius-xs);
  border: 1px solid var(--report-border);
  background: var(--cyan);
}
.sc-bar.ink { background: var(--report-white); }

/* Badges */
.badge {
  display: inline-block;
  font-size: var(--t-small);
  font-weight: 400;
  letter-spacing: 0.5px;
  padding: 0 16px;
  border-radius: var(--radius-full);
  background: var(--report-white);
  border: 1px solid var(--report-ink);
  color: var(--report-ink);
}

.badge.high   { background: var(--report-green); color: var(--report-white); }
.badge.med    { background: var(--report-amber); color: var(--report-white); }
.badge.low    { background: var(--report-red); color: var(--report-white); }
.badge.rising { background: var(--report-white); color: var(--report-ink); }
.row-rising .badge.rising { border: 1px solid var(--cyan); border-radius: var(--radius-full); }

/* T2 — scorecard badge variants */
.badge.badge-positive { background: var(--white); border: 1px solid var(--band-excellent); color: var(--report-ink); }
.badge.badge-neutral  { background: var(--gray-light);          border: none;                                       color: var(--report-ink); }


/* ═══════════════════════════════════════════════════════════════════════════
   T3 — HEAT MAP TABLE
   Intensity patterns across many entities × many attributes.
   ═══════════════════════════════════════════════════════════════════════════ */

.mi-heatmap {
  width: 100%;
  border-collapse: collapse;
  /* Fixed layout so every data column is equal width regardless of header
     length (APAC/LATAM no longer wider than NA/EU) per Christine, 1 June 2026.
     Was: auto layout (columns sized to content). */
  table-layout: fixed;
}

.mi-heatmap th {
  font-size: var(--t-small);
  font-weight: var(--font-weight-medium);
  color: var(--report-ink);
  letter-spacing: 0.06em;
  padding: var(--spacing-2) var(--spacing-3);
  text-align: center;
  /* Header-row divider: gray-dark 1px, consistent with every component/table
     header row (Christine, 1 June 2026). Was: 1.5px var(--report-ink). */
  border-bottom: 1px solid var(--gray-dark);
}

.mi-heatmap thead + tbody tr:first-child td { border-top: none; }

.mi-heatmap th.row-header {
  text-align: left;
  /* Defined width drives the fixed layout: the label column takes this share
     and the data columns split the remainder equally (Christine, 1 June 2026).
     Was: only min-width: 130px (auto layout). */
  width: 30%;
  min-width: 130px;
}

.mi-heatmap td {
  padding: var(--spacing-2) var(--spacing-3);
  text-align: center;
  /* Horizontal row dividers white (matches the assessment-heatmap-grid's
     white-gap look — the vertical dividers are already white). Christine,
     1 June 2026. Was: 1px solid var(--report-border). */
  border-bottom: 1px solid var(--report-white);
  border-right: 2px solid var(--report-white);
  /* Smaller text inside the coloured squares so the grid reads denser/cleaner
     (sits below the 14px column headers). Christine, 1 June 2026.
     Was: var(--t-body) (15px). The left row-label keeps --t-body via its own
     rule below. */
  font-size: var(--text-xs);
  /* Lighter numerals inside the coloured cells per Christine (31 May 2026).
     Was: font-weight var(--font-weight-medium). */
  font-weight: var(--font-weight-light);
}

.mi-heatmap td:last-child { border-right: none; }

.mi-heatmap td.row-label {
  text-align: left;
  font-size: var(--t-body);
  font-weight: var(--font-weight-light);
  color: var(--report-ink);
}

/* Heatmap intensity ladder — band-aligned palette matching the radar
   colour ladder (low → high: pink → coral → amber → mint → blue), all
   at low opacity so a dense grid still reads as a soft wash. Values
   trace to canonical tokens via color-mix; never hardcode hex. */
/* T3 — Heat scale: monochrome blue, increasing alpha = higher value.
   5 levels (heat-1…heat-5), now matching the assessment-heatmap-grid ladder
   (8/16/28/45/65%) so the grid reads as a soft wash instead of heavy saturated
   blocks — the top level caps at 65% rather than full hue (Christine, 1 June
   2026. Was: 14/28/46/70/100, top = FULL hue). heat-0 = empty/white (not a
   level). heat-hl is the top-of-scale standout cell (65% + semibold). */
/* Intensity ladder — see frame.css --heatmap-hue token. */
.mi-heatmap .heat-0 { background: var(--report-white); color: var(--report-ink); }
.mi-heatmap .heat-1 { background: color-mix(in srgb, var(--heatmap-hue) 8%, transparent);  color: var(--report-ink); }
.mi-heatmap .heat-2 { background: color-mix(in srgb, var(--heatmap-hue) 16%, transparent); color: var(--report-ink); }
.mi-heatmap .heat-3 { background: color-mix(in srgb, var(--heatmap-hue) 28%, transparent); color: var(--report-ink); }
.mi-heatmap .heat-4 { background: color-mix(in srgb, var(--heatmap-hue) 45%, transparent); color: var(--report-ink); }
.mi-heatmap .heat-5 { background: color-mix(in srgb, var(--heatmap-hue) 65%, transparent); color: var(--report-ink); }

/* ── Magnitude bar ramp ──────────────────────────────────────
   Token-driven 5%→100% opacity gradient for magnitude bars
   (over/under spend, contribution size, etc.). Single hue from
   --bar-ramp-hue (cyan by default), opacity-only — same family as
   the heat ladder above. .bar-ramp-h fills left→right;
   .bar-ramp-v fills bottom→top. */
.bar-ramp-h {
  background: linear-gradient(to right,
    color-mix(in srgb, var(--bar-ramp-hue) 5%, transparent),
    color-mix(in srgb, var(--bar-ramp-hue) 100%, transparent));
}
.bar-ramp-v {
  background: linear-gradient(to top,
    color-mix(in srgb, var(--bar-ramp-hue) 5%, transparent),
    color-mix(in srgb, var(--bar-ramp-hue) 100%, transparent));
}

.mi-heatmap .heat-hl {
  /* Capped at 65% to match the lightened ladder (matches ahm-cell--excellent).
     Was: var(--heatmap-hue) (full hue). */
  background: color-mix(in srgb, var(--heatmap-hue) 65%, transparent);
  color: var(--report-ink);
  font-weight: var(--font-weight-semibold);
}

/* Low → High gradient legend — right-aligned beneath the table per
   Christine (May 27 2026). The table already anchors the eye on the
   left; the legend reads cleaner tucked to the right edge. */
.mi-heatmap-legend {
  margin-top: var(--spacing-3);
  display: flex;
  gap: var(--spacing-2);
  align-items: center;
  justify-content: flex-end;
  font-size: var(--t-small);
  color: var(--report-ink);
}

/* Legend — 5 swatches matching the 5 heat levels (8→65%, lightened to match
   the assessment-heatmap-grid; Christine 1 June 2026. Was: 14→100%). */
.mi-heatmap-scale         { display: inline-flex; gap: 0; }
.mi-heatmap-scale span    { width: 18px; height: 10px; display: inline-block; }
.mi-heatmap-scale span:nth-child(1) { background: color-mix(in srgb, var(--heatmap-hue) 8%, transparent); }
.mi-heatmap-scale span:nth-child(2) { background: color-mix(in srgb, var(--heatmap-hue) 16%, transparent); }
.mi-heatmap-scale span:nth-child(3) { background: color-mix(in srgb, var(--heatmap-hue) 28%, transparent); }
.mi-heatmap-scale span:nth-child(4) { background: color-mix(in srgb, var(--heatmap-hue) 45%, transparent); }
.mi-heatmap-scale span:nth-child(5) { background: color-mix(in srgb, var(--heatmap-hue) 65%, transparent); }

.mi-heatmap-hl-note {
  margin-left: var(--spacing-3);
  color: var(--report-ink);
  font-size: var(--t-small);
}


/* ═══════════════════════════════════════════════════════════════════════════
   S1 — HORIZONTAL TIMELINE (above/below axis)
   Chronological milestones alternating above and below a central axis.
   ═══════════════════════════════════════════════════════════════════════════ */

.mi-timeline-wrap {
  position: relative;
  padding: var(--spacing-6) 0;
  /* No band frame. The top/bottom rules Christine asked for belong on each CARD
     in its own accent colour (see .mi-timeline-card), not on the grey band; the
     band's bottom rule also duplicated the section divider beneath it, leaving a
     double line (Christine, 1 June 2026 → updated). Was:
     border-top/border-bottom: 1px solid var(--report-border). */
  /* Height is now CONTENT-DRIVEN (Christine, 1 June 2026): every column is a
     two-row grid and carries its card height in BOTH halves (real card + a
     hidden ghost mirror, see timeline.html), so the tallest card anywhere sets a
     single shared half-height. The wrap therefore reserves exactly as much room
     as the content needs — paragraph-heavy cards get more room, sparse timelines
     stay compact — instead of a fixed budget that overflowed once cards carried a
     descriptive paragraph. Was: min-height: 380px (originally 280px, then 320px). */
  /* Fixed connector length between the dot (on the axis) and the card edge. */
  --tl-stem: 30px;
  /* Cards use width:140% centered in their track (20% overlap each side).
     overflow-x:visible lets those edges bleed into adjacent space without
     clipping — scroll would hide the very card portions the overlap creates. */
  overflow-x: visible;
}

.mi-timeline-axis {
  position: absolute;
  top: 50%;
  left: 0;
  right: 0;
  height: 2px;
  background: var(--navy);
  transform: translateY(-50%);
  z-index: 0;
}

.mi-timeline-cols {
  display: grid;
  grid-auto-flow: column;
  /* minmax(0, 1fr) (not 1fr) so a column can shrink below its content's
     intrinsic min-width — otherwise a long unbreakable word or a wide card
     blows the track out past the wrap and the edge columns get clipped
     (Christine, 1 June 2026). Was: grid-auto-columns: 1fr. */
  grid-auto-columns: minmax(0, 1fr);
  gap: var(--spacing-4);
  position: relative;
  z-index: 1;
}

.mi-timeline-col {
  /* Two equal rows = top half (above the axis) and bottom half (below). Keeping
     them equal (1fr 1fr) keeps the axis centred. Each column places its real card
     in one half and a hidden ghost mirror in the other (see timeline.html), so
     both halves grow to the same height and — across all columns, which stretch to
     the tallest — the tallest card sets a single shared half-height. This makes
     the height content-driven (Christine, 1 June 2026). Was: flex column with a
     fixed min-height (332px) holding a single absolutely-positioned card. */
  display: grid;
  grid-template-rows: 1fr 1fr;
  position: relative;       /* containing block for the absolute dot/stem */
}

/* Timeline accent (Christine, 1 June 2026). Set ONE colour as a custom property
   on the column so every descendant (year, dot, connector stem, card rules)
   inherits it. Every item is cyan — a single uniform colour so the accent can't
   be read as a severity/severability signal (a controversy timeline shouldn't
   imply some events are "worse" via colour). Was an 8-item cycle keyed off
   :nth-child(8n+N): y1 kicker03, y2 kicker04, y3 cyan, y4 kicker06, y5 kicker07,
   y6 kicker08, y7 kicker09, y8 kicker10; before that a 4-cycle (cyan/kicker07/
   purple/kicker11). */
.mi-timeline-col { --tl-accent: var(--cyan); }

/* Axis-anchored layout (Christine, 1 June 2026 → updated): the dot sits ON the
   axis OUTSIDE the card, and a fixed-length stem connects the card edge down/up
   to the dot. The card, stem and dot are all absolutely positioned against the
   column (which keeps its min-height so its 50% lines up with the axis at the
   wrap's 50%). Was: an in-flow flex stack (card → stem → dot → 50% spacer) whose
   tall cards overflowed across the axis, hiding the dot inside the card. */

/* Ghost mirror: a hidden copy of the card placed in the OPPOSITE half so that
   half grows to the same height, keeping the two rows equal and the axis centred
   (Christine, 1 June 2026). visibility:hidden preserves its size (so it reserves
   height) while hiding all its ink, including the accent rules. Was: an empty
   .mi-timeline-spacer set to display:none under the absolute layout. */
.mi-timeline-card--ghost { visibility: hidden; }
.mi-timeline-spacer { display: none; }

.mi-timeline-stem {
  position: absolute;
  /* Default centre; overridden per row below to track the card centre. */
  left: 50%;
  transform: translateX(-50%);
  width: 1px;
  height: var(--tl-stem);
  /* Connector line leading to the card takes the item's accent colour
     (Christine, 1 June 2026). Was: var(--gray-light). */
  background: var(--tl-accent);
  z-index: 2;
}
/* Stem runs from the axis (50%) outward by --tl-stem toward the card. */
.mi-timeline-col.above .mi-timeline-stem { bottom: 50%; top: auto; }
.mi-timeline-col.below .mi-timeline-stem { top: 50%; bottom: auto; }
/* Align stem with the horizontal centre of the card.
   Above cards are left-anchored at 170% width → centre = 85% of track.
   Below cards are right-anchored at 170% width → centre = 100% − 85% = 15%. */
.mi-timeline-col.above .mi-timeline-stem { left: 95%; }
.mi-timeline-col.below .mi-timeline-stem { left: 5%; }

/* Focus element removed — all items render evenly, so .hl no longer differs
   from the base stem (Christine, 1 June 2026). Was: background a legacy bullet-palette colour (now removed). */
.mi-timeline-stem.hl { background: var(--tl-accent); }

.mi-timeline-dot {
  width: 10px;
  height: 10px;
  border-radius: var(--radius-full);
  /* Dot takes the item's accent colour (Christine, 1 June 2026).
     Was: var(--gray-light). */
  background: var(--tl-accent);
  border: none;
  /* Pin to the axis, outside the card. Column is position:relative and the axis
     sits at top:50% of the wrap (which matches col mid since the col min-height
     equals the wrap's inner height). */
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 3;
}
/* Align dot with card centre — same offsets as the stem above. */
.mi-timeline-col.above .mi-timeline-dot { left: 95%; }
.mi-timeline-col.below .mi-timeline-dot { left: 5%; }

/* Focus dot removed — even with every other dot (Christine, 1 June 2026).
   Was: width/height 15px; background a legacy bullet-palette colour (now removed). */
.mi-timeline-dot.hl {
  width: 10px;
  height: 10px;
  background: var(--tl-accent);
  border-color: transparent;
}

.mi-timeline-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 2px;
  /* Full box border in the accent colour with a light cyan wash background.
     Christine mockup, 12 Jun 2026. Was: top + bottom rules only, white fill. */
  background: var(--report-white);
  border: 1.5px solid var(--navy);
  border-radius: 8px;
  padding: 14px 12px;
  /* 140% of column track width — 40% overflow into adjacent space.
     Above cards align left (overflow extends right); below cards align right
     (overflow extends left) — see per-row rules below.
     Same-side cards are 2 tracks apart so they never collide at 140%;
     opposite-side (above↔below) cards cross horizontally but are on opposite
     faces of the axis so there is no visual clash.
     The 40% extra width prevents the character-level word-splitting
     ("Microsof t") seen when cards were confined to the ~116px 1fr track.
     Was: width:100%; justify-self:stretch — then max(100%,140px);center. */
  width: 190%;
  z-index: 2;
}
/* Place each card in its half and pull it off the axis by the stem length, so the
   dot (on the axis) always sits OUTSIDE the card with the stem bridging the gap.
   Row 1 = the top half (an ABOVE column's real card, or a BELOW column's ghost);
   row 2 = the bottom half (a BELOW column's real card, or an ABOVE column's
   ghost). Was: absolute bottom/top: calc(50% + var(--tl-stem)). */
.mi-timeline-col.above > .mi-timeline-card:not(.mi-timeline-card--ghost),
.mi-timeline-col.below > .mi-timeline-card--ghost {
  grid-row: 1;
  align-self: end;
  margin-bottom: var(--tl-stem);
}
.mi-timeline-col.above > .mi-timeline-card--ghost,
.mi-timeline-col.below > .mi-timeline-card:not(.mi-timeline-card--ghost) {
  grid-row: 2;
  align-self: start;
  margin-top: var(--tl-stem);
}

/* Stagger: same-side cards (which overlap at 190% width) sit at different distances
   from the axis, reducing clutter. The pattern inverts between rows so that when an
   above card is close (20px) its paired below neighbour is far (40px), and vice versa.
   Cycle of 4: nth-child 1(above-odd)=20px base, 2(below-odd)=40px, 3(above-even)=40px,
   4(below-even)=20px base. --tl-stem drives both stem height and card margin, so one
   variable handles both automatically. */
.mi-timeline-col:nth-child(4n+2),
.mi-timeline-col:nth-child(4n+3) { --tl-stem: 100px; }

/* Directional alignment: above cards anchor left (40% overflow extends right),
   below cards anchor right (40% overflow extends left). This applies to both
   the real card and its ghost so height reservation is symmetrical.
   Was: justify-self:center on all cards + translateX(20px) on below. */
.mi-timeline-col.above > .mi-timeline-card { justify-self: start; }
.mi-timeline-col.below > .mi-timeline-card { justify-self: end; }

/* Highlight: solid light-blue wash (not transparent) so the axis line
   beneath cannot show through. Built by mixing the canonical
   band-excellent token with report-white at 12 % — same recipe
   as the lightest heatmap tier, kept opaque. */
/* Focus card removed — even with every other card (Christine, 1 June 2026).
   Was: background color-mix(a legacy bullet-palette colour 10%, report-white); border: none. */
.mi-timeline-card.hl {
  /* Same white fill as the base card.
     Was: color-mix(in srgb, var(--cyan) 6/12%, var(--report-white)). */
  background: var(--report-white);
  border: 1.5px solid var(--navy);
}

.mi-timeline-card.hl .mi-timeline-card-date {
  /* Year text now cyan (Christine, 1 June 2026). Was: var(--report-ink) (black);
     before that var(--tl-accent) (per-item accent), then medium weight. */
  font-weight: var(--font-weight-bold);
  color: var(--cyan);
}
.mi-timeline-card.hl .mi-timeline-card-name,
.mi-timeline-card.hl .mi-timeline-card-body {
  color: var(--report-ink);
}

.mi-timeline-card-date {
  font-size: var(--chart-val-size);
  /* Year bolded (Christine, 1 June 2026). Was: var(--font-weight-medium) (500). */
  font-weight: var(--font-weight-bold);
  /* Year text now cyan (Christine, 1 June 2026). Was: var(--report-ink) (black);
     before that var(--tl-accent) (per-item accent), then var(--chart-val-color).
     Now that every item is cyan, --tl-accent would also work, but cyan is set
     explicitly to keep the year colour independent of any future accent change. */
  color: var(--cyan);
  line-height: 1.3;
}

.mi-timeline-card-name {
  font-size: var(--chart-name-size);
  font-weight: var(--chart-name-wt);
  color: var(--chart-name-color);
  line-height: 1.3;
  margin-bottom: 15px;
  /* break-word (not anywhere) so the browser breaks at word/hyphen boundaries
     first and only splits inside a word as a last resort — prevents the
     character-level splitting ("Microsof t") seen with overflow-wrap:anywhere
     at narrow column widths. hyphens:auto adds soft hyphenation at syllable
     breaks when a word must split. Was: overflow-wrap:anywhere. */
  overflow-wrap: break-word;
  hyphens: auto;
}

.mi-timeline-card-body {
  font-size: var(--t-small);
  font-weight: var(--font-weight-light);
  color: var(--report-ink);
  line-height: 1.4;
  /* Same rationale as .mi-timeline-card-name above. */
  overflow-wrap: break-word;
  hyphens: auto;
}


/* ═══════════════════════════════════════════════════════════════════════════
   S2 — CAPITAL EVENT CARDS (2×2 grid)
   4 dated capital events in a 2-column grid.
   ═══════════════════════════════════════════════════════════════════════════ */

.mi-capital-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  /* 24px gap to match the section rhythm elsewhere in the report.
     Christine 29 May 2026. */
  gap: var(--spacing-6);
}

/* White floating card (white fill, soft shadow, no border). The .hl card
   shares chrome; the amount (the "stat") reads in cyan. Christine 29 May 2026.
   Shadow uses --shadow-section to match the rest of the gallery cards (stat
   cards, stat-callouts, report containers). Was: --shadow-lg (the heavier
   key-findings-grid shadow), which read as a stronger drop shadow than the
   surrounding cards. */
.mi-capital-card,
.mi-capital-card.hl {
  background: var(--white);
  border: none;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-section);
  /* Match the standard report container padding (28px / 35px) so the
     capital cards share the rhythm of every other report container.
     Christine 29 May 2026. */
  padding: var(--report-container-pad-y) var(--report-container-pad-x);
}

/* Capital cards share the SAME label / value / sublabel recipe as
   stat-callouts (charts.css ~245) so the two components read as one
   family. Year = label, amount = value, name = note. Body is plain
   prose. Do not re-size per component. */
.mi-capital-year {
  display: block;
  font-size: var(--card-heading-size);
  font-weight: var(--card-heading-weight);
  letter-spacing: var(--card-heading-spacing);
  color: var(--card-heading-color);
  line-height: 1.3;
  margin: 0 0 var(--spacing-1);
}

.mi-capital-year.hl   { color: var(--card-heading-color); }

.mi-capital-amount {
  display: block;
  font-size: var(--card-value-size);
  /* 700 weight — Christine 29 May 2026. */
  font-weight: var(--font-weight-bold);
  font-variant-numeric: tabular-nums;
  letter-spacing: normal;
  color: var(--cyan);
  line-height: 1.15;
  margin: 0;
  /* Christine 29 May 2026 — 20px of breathing room above the stat so the
     amount separates cleanly from the year label. */
  padding-top: var(--spacing-5);
  text-transform: capitalize;
}

.mi-capital-amount.hl { color: var(--cyan); }

.mi-capital-name {
  display: block;
  font-size: var(--card-source-size);
  font-weight: 300;
  letter-spacing: normal;
  color: var(--card-source-color);
  line-height: 1.4;
  margin: var(--spacing-2xs) 0 var(--spacing-2);
}

.mi-capital-body {
  display: block;
  font-size: var(--t-body);
  font-weight: var(--t-body-wt);
  color: var(--report-ink);
  line-height: var(--t-body-lh);
}


/* ═══════════════════════════════════════════════════════════════════════════
   KEY FINDINGS LIST
   Numbered editorial list used on every Research report.
   ═══════════════════════════════════════════════════════════════════════════ */

.mi-key-findings {
  list-style: none;
  padding: 0 0 var(--spacing-5);
  margin: 0;
  counter-reset: findings;
  display: flex;
  flex-direction: column;
}

.mi-key-findings li {
  counter-increment: findings;
  display: grid;
  grid-template-columns: 24px 1fr;
  gap: 0;
  padding: var(--spacing-3) 0;
}

/* Hairline divider between findings — canonical report-border token,
   skipped on the first item so it sits flush with the section head. */
.mi-key-findings li + li {
  border-top: 1px solid var(--report-border);
}

.mi-key-findings li::before {
  content: counter(findings) ".";
  font-size: var(--t-body);
  font-weight: 600;
  color: var(--report-ink);
  margin-right: var(--spacing-2);
  align-self: start;
  line-height: var(--t-body-lh);
}

.mi-key-findings li p {
  font-size: var(--t-body);
  font-weight: var(--t-body-wt);
  line-height: var(--t-body-lh);
  color: var(--report-ink);
  margin: 0;
}

.mi-key-findings li p em {
  font-style: italic;
  color: var(--report-ink);
}

.mi-key-findings--grid li p em {
  font-style: italic;
  font-weight: var(--font-medium);
}


/* ═══════════════════════════════════════════════════════════════════════════
   KEY FINDINGS — white card grid (research report)
   Modifier on .mi-key-findings: lays the findings out as elevated white
   containers (rounded, soft shadow, no border, no tint fill) each led by a
   cyan numeral. Render-time only — the plain list (no modifier) and other
   report types are untouched. Christine 29 May 2026.
   ═══════════════════════════════════════════════════════════════════════════ */
.mi-key-findings--grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--spacing-6);
  /* 30px after the last card row, before any prose that follows within the
     same section. padding-bottom stays 0 to avoid stacking with the section-
     level gap; margin-bottom is the right lever here (intra-section spacing,
     not inter-section). */
  padding-bottom: 0;
  margin-bottom: 30px;
}

.mi-key-findings--grid li {
  display: block;
  padding: var(--spacing-6);
  border: none;
  border-radius: var(--radius-lg);
  background: var(--white);
  box-shadow: var(--shadow-lg);
}

/* Drop the base hairline divider — each card floats in its own container. */
.mi-key-findings--grid li + li {
  border-top: none;
}

/* Cyan "Finding N" heading on its own line above the text — gives each
   floating card a titled anchor. Overrides the base ::before content
   (counter(findings) ".") with a labelled form. */
.mi-key-findings--grid li::before {
  display: block;
  content: "Finding " counter(findings);
  font-size: var(--text-xl);
  font-weight: var(--font-weight-bold);
  color: var(--cyan);
  margin: 0 0 var(--spacing-3);
  line-height: 1;
}

.mi-key-findings--grid li p {
  max-width: none;
}

/* Collapse to a single column on narrow viewports. */
@media (max-width: 700px) {
  .mi-key-findings--grid {
    grid-template-columns: 1fr;
  }
}


/* ═══════════════════════════════════════════════════════════════════════════
   SNAPSHOT SECTION PREVIEWS
   Section title + first paragraph preview for snapshot view.
   ═══════════════════════════════════════════════════════════════════════════ */

.snapshot-section-preview {
  padding: var(--spacing-3) 0;
}

.snapshot-section-preview .mi-eyebrow {
  margin-bottom: var(--spacing-1);
}

.snapshot-section-title {
  font-size: var(--t-section);
  font-weight: 600;
  line-height: 1.3;
  color: var(--report-ink);
  margin: 0 0 var(--spacing-2) 0;
}

.snapshot-section-preview .rpt-standfirst {
  margin-bottom: var(--spacing-2);
}

.snapshot-section-preview .rpt-para-body {
  color: var(--report-muted);
}


/* ═══════════════════════════════════════════════════════════════════════════
   INTEL GRID — SCORECARD TILES
   3-up elevated tiles, stat-card layout (label / cyan value / note).
   ═══════════════════════════════════════════════════════════════════════════ */

.mi-intel-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--spacing-6);
}

/* Each intel item is an elevated card floating bare on the canvas, laid out
   like a stat card: label (small) / value (large cyan bold) / note (light).
   No numbers. Christine 30 May 2026. */
.mi-intel-item {
  display: block;
  background: var(--report-white);
  border: 1px solid var(--report-border);
  border-radius: var(--radius-lg);
  padding: var(--report-container-pad-y) var(--report-container-pad-x);
}

.mi-intel-label {
  font-size: var(--card-heading-size);
  font-weight: var(--card-heading-weight);
  letter-spacing: var(--card-heading-spacing);
  color: var(--card-heading-color);
  line-height: 1.3;
  margin: 0 0 var(--spacing-1);
}

.mi-intel-value {
  font-size: var(--card-value-size);
  font-weight: var(--font-weight-bold);
  color: var(--cyan);
  line-height: 1.15;
  margin: 0;
  padding-top: var(--spacing-5);
}

/* When the value is a score (NN/100 via score_smart) it renders inside
   .rpt-score, whose canonical recipe shrinks it. Inside an intel tile the
   score must read at the large value size with the number + suffix in cyan
   bold, so override the canonical recipe here (same as stat callouts). */
.mi-intel-value .rpt-score { font-size: var(--card-value-size) !important; }
.mi-intel-value .rpt-score .rpt-score-n {
  color: var(--cyan) !important;
  font-weight: var(--font-weight-bold) !important;
}
.mi-intel-value .rpt-score .sv-score-suffix {
  font-size: var(--card-value-size) !important;
  font-weight: var(--font-weight-bold) !important;
}

.mi-intel-note {
  font-size: var(--card-source-size);
  font-weight: var(--card-source-weight);
  color: var(--card-source-color);
  line-height: 1.4;
  margin: var(--spacing-2xs) 0 0;
}

/* Mobile: collapse the scorecard tiles to a single column. */
@media (max-width: 600px) {
  .mi-intel-grid { grid-template-columns: 1fr; }
}


/* ═══════════════════════════════════════════════════════════════════════════
   META BAR
   Report identity row below the cover standfirst.
   ═══════════════════════════════════════════════════════════════════════════ */

.mi-meta-line {
  display: flex;
  align-items: center;
  gap: var(--spacing-2);
  font-size: var(--t-small);
  font-weight: var(--font-weight-medium);
  color: var(--report-ink);
  margin-top: var(--spacing-3);
}

.mi-meta-sep { color: var(--report-border); }

/* Alias used by newer templates */
.rpt-meta-line { display: flex; align-items: center; gap: var(--spacing-2); font-size: var(--chart-heading-size); font-weight: var(--chart-heading-wt); color: var(--chart-heading-color); margin-top: 0; }
.rpt-meta-sep  { color: var(--report-border); }


/* ═══════════════════════════════════════════════════════════════════════════
   SOURCES & METHODOLOGY
   Final section of every Research report.
   ═══════════════════════════════════════════════════════════════════════════ */

#p-brief { margin-bottom: 20px; }

.mi-sources-section {
  padding: 50px 0 80px;
  width: 100%;
  max-width: none;
  border-radius: 8px;
  background: transparent;
  border: none;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.mi-sources-section > * {
  width: 100%;
  max-width: 800px;
}

.mi-sources-block {
  border-top: none;
  padding-top: var(--spacing-6);
  margin-bottom: 0;
}

.mi-sources-block:first-child { border-top: none; }
.mi-sources-block + .mi-sources-block { margin-top: 24px; }

.mi-sources-block-title {
  font-size: var(--chart-heading-size);
  font-weight: var(--chart-heading-wt);
  color: var(--chart-heading-color);
  margin-bottom: 0;
}

.mi-sources-disclaimer {
  font-size: var(--t-small);
  font-weight: var(--font-weight-light);
  font-style: italic;
  margin-top: 8px;
  line-height: 1.75;
  color: var(--report-ink);
  margin-bottom: var(--spacing-2);
}

.mi-sources-disclaimer.muted { color: var(--report-ink); }

.mi-sources-list {
  font-size: var(--t-small);
  font-weight: var(--font-weight-light);
  color: var(--report-ink);
  line-height: 2.2;
  margin-top: 12px;
}

.mi-sources-list em { font-style: italic; }

.fw-sources-list {
  margin-bottom: var(--spacing-6);
  font-style: italic;
}

.fw-sources-heading {
  font-size: var(--chart-heading-size);
  font-weight: var(--chart-heading-wt);
  letter-spacing: 1.2px;
  color: var(--report-ink);
  margin-bottom: var(--spacing-3);
}

.fw-source-item {
  display: flex;
  align-items: baseline;
  gap: var(--spacing-3);
  padding: 6px 0;
  border-bottom: 0.5px solid var(--report-ink-10);
  font-size: var(--t-small);
  line-height: 1.6;
}

.fw-source-item:last-child { border-bottom: none; }

.fw-source-name {
  font-weight: var(--font-weight-normal);
  color: var(--report-ink);
  text-decoration: none;
  flex-shrink: 0;
}

.fw-source-name:hover { text-decoration: underline; }

.fw-source-used-for {
  font-weight: var(--font-weight-light);
  color: var(--report-ink-60);
}

.fw-source-accessed {
  font-weight: var(--font-weight-light);
  color: var(--report-ink-35);
  font-size: var(--t-small);
  margin-left: auto;
  flex-shrink: 0;
}

.fw-frameworks-used {
  margin-top: 32px;
  padding-top: 24px;
  border-top: 1px solid var(--report-ink-10);
  font-style: italic;
}

#p-frameworks .fw-frameworks-used {
  margin-top: 0;
  padding-top: 0;
  border-top: none;
}

#p-frameworks .mi-sources-block {
  padding-top: 0;
}

.fw-frameworks-heading {
  font-family: var(--font-family-display);
  font-size: var(--t-base);
  font-weight: var(--font-weight-medium);
  color: var(--report-ink);
  margin-bottom: 8px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.fw-frameworks-intro {
  /* Footer-prose recipe — see frame.css --footer-body-* tokens. */
  font-size: var(--footer-body-size);
  font-weight: var(--footer-body-weight);
  color: var(--footer-body-color);
  line-height: var(--footer-body-lh);
  margin-bottom: 16px;
}

.fw-framework-entry {
  /* Footer-prose recipe — see frame.css --footer-body-* tokens. */
  font-size: var(--footer-body-size);
  font-weight: var(--footer-body-weight);
  color: var(--footer-body-color);
  line-height: var(--footer-body-lh);
  margin-bottom: 12px;
}

.fw-framework-name {
  font-weight: var(--footer-body-strong-wt);
  color: var(--footer-body-strong-color);
}

.mi-gap-note {
  background: none;
  border-radius: var(--radius-sm);
  padding: 0;
  margin-top: 16px;
  font-size: var(--t-small);
  font-weight: var(--font-weight-light);
  line-height: 1.7;
  color: var(--report-ink);
}

.mi-conflict-note {
  font-size: var(--t-small);
  font-weight: var(--font-weight-light);
  line-height: 1.75;
  color: var(--report-ink);
}

/* Footnote reference superscript */
.footnote-ref {
  font-size: var(--t-small);
  color: var(--cyan);
  vertical-align: super;
  font-weight: var(--font-weight-medium);
  line-height: 0;
  margin-left: 1px;
}

/* source-num and source-text are in components.css — do not duplicate here */


/* ═══════════════════════════════════════════════════════════════════════════
   VENDOR / ENTITY MATRIX TABLE
   Grid table: entity columns × dimension rows.
   ═══════════════════════════════════════════════════════════════════════════ */

.mi-matrix {
  width: 100%;
  border-collapse: collapse;
}

.mi-matrix-col-label {
  font-size: var(--chart-name-size);
  font-weight: var(--chart-name-wt);
  color: var(--chart-name-color);
  padding: 0 var(--spacing-3) var(--spacing-4);
  text-align: center;
  border-bottom: 1.5px solid var(--report-ink);
}

.mi-matrix-col-label.hl { color: var(--chart-name-hl-color); font-weight: var(--chart-name-hl-wt); }

.mi-matrix-row-label {
  font-size: var(--chart-name-size);
  font-weight: var(--chart-name-wt);
  color: var(--chart-name-color);
  padding: var(--spacing-4) var(--spacing-3) var(--spacing-4) 0;
  border-bottom: 1px solid var(--report-border);
  vertical-align: middle;
}

.mi-matrix-cell {
  font-size: var(--t-body);
  font-weight: var(--font-weight-light);
  color: var(--report-ink);
  padding: var(--spacing-4) var(--spacing-3);
  border-bottom: 1px solid var(--report-border);
  border-left: 1px solid var(--report-border);
  text-align: center;
  background: var(--report-white);
  vertical-align: middle;
  line-height: 1.5;
}

.mi-matrix-cell.hl {
  background: var(--cyan);
  color: var(--report-white);
  font-weight: var(--font-weight-medium);
}


/* ═══════════════════════════════════════════════════════════════════════════
   SCENARIO ROWS (probability-square variant)
   Risk scenario analysis with visual probability squares.
   ═══════════════════════════════════════════════════════════════════════════ */

.mi-scenario-rows {
  display: flex;
  flex-direction: column;
  gap: 0;
}

.mi-scenario-row-item {
  padding: 20px;
  border: 1px solid var(--report-border);
  border-top: none;
  background: var(--report-white);
}

.mi-scenario-row-item:first-child { border-top: 1px solid var(--report-border); border-radius: 6px 6px 0 0; }
.mi-scenario-row-item:last-child  { border-radius: 0 0 6px 6px; }

.mi-scenario-row-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: var(--spacing-2);
}

.mi-scenario-row-name {
  font-size: var(--chart-name-size);
  font-weight: var(--chart-name-wt);
  color: var(--chart-name-color);
}

.mi-scenario-row-meta {
  display: flex;
  align-items: center;
  gap: var(--spacing-3);
}

.mi-scenario-pct    { font-size: 20px; font-weight: var(--chart-val-hl-wt); color: var(--chart-val-color); }
.mi-scenario-pct.hl { color: var(--chart-val-hl-color); }

.mi-scenario-squares,
.mi-scenario-squares { display: flex; gap: 3px; }

.mi-scenario-sq    { width: 12px; height: 12px; border-radius: 2px; background: var(--gray-light); }
.mi-scenario-sq.on { background: var(--report-ink); }
.mi-scenario-sq.hl { background: var(--cyan); }

.mi-scenario-bar-track {
  height: 6px;
  background: var(--gray-light);
  border-radius: 3px;
  overflow: hidden;
  margin-bottom: 14px;
}

.mi-scenario-bar-fill    { height: 100%; border-radius: 3px; background: var(--report-ink); }
.mi-scenario-bar-fill.hl { background: var(--cyan); }

/* Per-case colour ladder — Bull (blue) · Base (amber) · Bear (pink).
   Modifier on the row scopes both filled squares (.on/.hl) and the bar-fill,
   so each scenario row reads in its own hue regardless of which is "highlighted". */
.mi-scenario-row-item--bull .mi-scenario-sq.on,
.mi-scenario-row-item--bull .mi-scenario-sq.hl,
.mi-scenario-row-item--bull .mi-scenario-bar-fill,
.mi-scenario-row-item--bull .mi-scenario-bar-fill.hl { background: var(--band-excellent); }

.mi-scenario-row-item--base .mi-scenario-sq.on,
.mi-scenario-row-item--base .mi-scenario-sq.hl,
.mi-scenario-row-item--base .mi-scenario-bar-fill,
.mi-scenario-row-item--base .mi-scenario-bar-fill.hl { background: var(--band-solid); }

.mi-scenario-row-item--bear .mi-scenario-sq.on,
.mi-scenario-row-item--bear .mi-scenario-sq.hl,
.mi-scenario-row-item--bear .mi-scenario-bar-fill,
.mi-scenario-row-item--bear .mi-scenario-bar-fill.hl { background: var(--cyan); }

.mi-scenario-row-title {
  font-size: var(--chart-name-size);
  font-weight: 500;
  font-style: italic;
  color: var(--chart-name-color);
  margin-bottom: var(--spacing-1);
  line-height: 1.4;
}

.mi-scenario-row-body {
  font-size: var(--t-body);
  font-weight: 300;
  color: var(--report-ink);
  line-height: var(--t-body-lh);
}


/* ═══════════════════════════════════════════════════════════════════════════
   POSITIONING MATRIX (2×2 quadrant with entity dots)
   Used by: Competitive Landscape and any quadrant-positioning analysis.
   ═══════════════════════════════════════════════════════════════════════════ */

.cl-matrix-wrap {
  width: 100%;
  position: relative; /* anchor for the bubble-matrix HTML label overlay (.bm-label-layer) */
}

.cl-matrix-legend {
  list-style: none;
  margin: 12px 0 30px;
  /* Default alignment for positioning-matrix: the matrix grid sits to the
     right of .cl-matrix-y-label-wrap (24px) inside .cl-matrix-outer, so the
     legend needs the same 24px inset to start where the gridline starts. */
  padding: 0 0 0 24px;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 4px 16px;
  font-size: 12px;
  color: var(--report-ink);
}

/* Bubble-matrix has its axis inside an SVG (viewBox 640, pad_l 48), not in a
   sibling y-label column — so the gridline starts at 48/640 = 7.5% of the
   container width. Detect that variant by the legend's sibling being a
   direct <svg> child of .cl-matrix-wrap. */
.cl-matrix-wrap:has(> svg) > .cl-matrix-legend {
  padding-left: 7.5%;
  /* The SVG already reserves ~40px of bottom padding below the axis
     (pad_b in bubble-matrix.html), so an additional 12px top margin reads
     as a much larger gap than positioning-matrix. Pull the legend up. */
  margin-top: -8px;
  /* Pack items together with flex flow instead of the wide auto-fill grid
     columns (which stretched each item to 1fr and spread them apart), matching
     positioning-matrix. (Christine, 31 May 2026.) */
  display: flex;
  flex-wrap: wrap;
  gap: 6px 14px;
}
/* Positioning-matrix legend: pack items together with a flex flow instead of
   the wide auto-fill grid columns (which stretched each item to 1fr and spread
   them apart). (Christine, 31 May 2026.) */
.cl-matrix-wrap:not(:has(> svg)) > .cl-matrix-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 14px;
}
.cl-matrix-legend-item {
  display: flex;
  align-items: baseline;
  gap: 8px;
  line-height: 1.4;
}
.cl-matrix-legend-key {
  font-weight: 600;
  min-width: 1.25em;
  color: var(--chart-name-color);
}

/* Per-entity legend key colour cycle — matches the dot colour cycle
   (A→pink, B→red, C→kicker16, D→cyan, E→kicker02, F→green, G→cyan,
   H→kicker06, I→kicker07, J→purple, then wraps). Shared with
   bubble-matrix, whose legend keeps lettered keys. ── */
.cl-matrix-legend-item:nth-child(10n+1)  .cl-matrix-legend-key { color: var(--pink); }
.cl-matrix-legend-item:nth-child(10n+2)  .cl-matrix-legend-key { color: var(--red); }
.cl-matrix-legend-item:nth-child(10n+3)  .cl-matrix-legend-key { color: var(--kicker16); }
.cl-matrix-legend-item:nth-child(10n+4)  .cl-matrix-legend-key { color: var(--band-strong); } /* D = cyan (band-strong) in positioning matrix */
.cl-matrix-legend-item:nth-child(10n+5)  .cl-matrix-legend-key { color: var(--kicker02); }
.cl-matrix-legend-item:nth-child(10n+6)  .cl-matrix-legend-key { color: var(--green); }
.cl-matrix-legend-item:nth-child(10n+7)  .cl-matrix-legend-key { color: var(--cyan); }
.cl-matrix-legend-item:nth-child(10n+8)  .cl-matrix-legend-key { color: var(--kicker06); }
.cl-matrix-legend-item:nth-child(10n+9)  .cl-matrix-legend-key { color: var(--kicker07); }
.cl-matrix-legend-item:nth-child(10n+10) .cl-matrix-legend-key { color: var(--purple); }

/* Leader key takes the leader dot's colour (purple/band-excellent)
   so the legend key visibly matches its dot. Name stays in ink so the
   entity reads as the highlighted one. ── */
.cl-matrix-legend-item.leader .cl-matrix-legend-key {
  font-weight: 600;
  color: var(--band-excellent);
}

/* Both matrices (positioning + bubble) dropped their in-chart A/B/C letters, so
   the legend key is a colour SWATCH (filled circle), not a letter. This now
   applies to EVERY .cl-matrix-wrap — bubble-matrix joined positioning here
   (was scoped :not(:has(> svg)) when only positioning used swatches). The
   lettered colour cycle above is legacy and harmless (keys render empty spans).
   NOTE: the positioning-only flex packing of the legend stays scoped via
   :not(:has(> svg)) elsewhere — only the swatch styling is shared. (Christine, 31 May 2026.) */
.cl-matrix-wrap .cl-matrix-legend-item { align-items: center; }
.cl-matrix-wrap .cl-matrix-legend-key {
  width: 10px;
  height: 10px;
  min-width: 0;
  border-radius: var(--radius-full);
  flex: none;
  display: inline-block;
}
/* Legend swatch colour cycle — SHARED 16-colour every-OTHER cycle for BOTH
   matrices (positioning + bubble now use the identical palette/order), so up to
   16 brands get distinct colours before repeating; kicker05 is last (effectively
   reserved for the user). Legend items have NO quadrant-labels first child, so a
   legend's child N matches the positioning dot cycle's child N+1 (same colour per
   entity). The swatch SHAPE above and the leader override (kicker05) below are
   also shared.
   (Christine, 31 May 2026. Was: re-split — positioning 16-colour every-other via
   :not(:has(> svg)); bubble 6-colour even cycle kicker02/04/06/08/10/12 via
   :has(> svg). Bubble now matches positioning, so re-merged into one cycle.) */
/* Starts at kicker02 (evens then odds) so the cycle no longer leads with pale
   kicker01; kicker05 last. (Christine, 31 May 2026. Was: started at kicker01.) */
.cl-matrix-wrap .cl-matrix-legend-item:nth-child(16n+1)   .cl-matrix-legend-key { background: var(--kicker02); }
.cl-matrix-wrap .cl-matrix-legend-item:nth-child(16n+2)   .cl-matrix-legend-key { background: var(--kicker04); }
.cl-matrix-wrap .cl-matrix-legend-item:nth-child(16n+3)   .cl-matrix-legend-key { background: var(--kicker06); }
.cl-matrix-wrap .cl-matrix-legend-item:nth-child(16n+4)   .cl-matrix-legend-key { background: var(--kicker08); }
.cl-matrix-wrap .cl-matrix-legend-item:nth-child(16n+5)   .cl-matrix-legend-key { background: var(--kicker10); }
.cl-matrix-wrap .cl-matrix-legend-item:nth-child(16n+6)   .cl-matrix-legend-key { background: var(--kicker12); }
.cl-matrix-wrap .cl-matrix-legend-item:nth-child(16n+7)   .cl-matrix-legend-key { background: var(--kicker14); }
.cl-matrix-wrap .cl-matrix-legend-item:nth-child(16n+8)   .cl-matrix-legend-key { background: var(--kicker16); }
.cl-matrix-wrap .cl-matrix-legend-item:nth-child(16n+9)   .cl-matrix-legend-key { background: var(--kicker01); }
.cl-matrix-wrap .cl-matrix-legend-item:nth-child(16n+10)  .cl-matrix-legend-key { background: var(--kicker03); }
.cl-matrix-wrap .cl-matrix-legend-item:nth-child(16n+11)  .cl-matrix-legend-key { background: var(--kicker07); }
.cl-matrix-wrap .cl-matrix-legend-item:nth-child(16n+12)  .cl-matrix-legend-key { background: var(--kicker09); }
.cl-matrix-wrap .cl-matrix-legend-item:nth-child(16n+13)  .cl-matrix-legend-key { background: var(--kicker11); }
.cl-matrix-wrap .cl-matrix-legend-item:nth-child(16n+14)  .cl-matrix-legend-key { background: var(--kicker13); }
.cl-matrix-wrap .cl-matrix-legend-item:nth-child(16n+15)  .cl-matrix-legend-key { background: var(--kicker15); }
.cl-matrix-wrap .cl-matrix-legend-item:nth-child(16n+16)  .cl-matrix-legend-key { background: var(--kicker05); }
/* User/leader = kicker05 (matches the user's highlighted dot/bubble). Shared. */
.cl-matrix-wrap .cl-matrix-legend-item.leader .cl-matrix-legend-key { background: var(--kicker05); }
.cl-matrix-legend-item.leader .cl-matrix-legend-name {
  font-weight: 600;
  color: var(--report-ink);
}

/* Charts that are too tall/wide to sit beside narrow insight text span the
   full width and let the insight paragraphs flow BELOW them instead of to the
   right. The fault-list (ranked risks) joins the matrix/heatmap here.
   Christine 29 May 2026. */
.rpt-chart-insight:has(.cl-matrix-wrap),
.rpt-chart-insight:has(.mi-heatmap),
.rpt-chart-insight:has(.fault-list) {
  grid-template-columns: 1fr;
}

.cl-matrix-outer {
  display: flex;
  align-items: stretch;
  gap: 0;
}

.cl-matrix-y-label-wrap {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  flex-shrink: 0;
}

.cl-matrix-y-label {
  font-size: var(--t-small);
  font-weight: var(--t-body-wt);
  color: var(--report-ink);
  transform: rotate(-90deg);
  white-space: nowrap;
}

.cl-matrix-inner {
  flex: 1;
  display: flex;
  flex-direction: column;
}

.cl-matrix-y-high {
  font-size: var(--t-small);
  font-weight: var(--font-weight-medium);
  color: var(--report-ink);
  text-align: right;
  padding-right: var(--spacing-2);
  padding-bottom: var(--spacing-1);
}

.cl-matrix-grid {
  flex: 1;
  min-height: 300px;
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 1fr 1fr;
  border: 1px dashed var(--chart-gridline);
  position: relative;
  overflow: hidden;
  /* Faint center cross splitting the box into 4 quadrants (per Christine,
     31 May 2026). Painted as background gradients so it sits behind the
     dots/labels; colour traces to the shared --chart-gridline token (was
     --report-border) so it matches every other chart's gridlines.
     Dashed (4/4) to match the dashed gridlines used by the other charts
     (stroke-dasharray: 4 4). The repeating gradients run along each line's
     length; background-size pins each to a 1px-wide/tall strip at centre. */
  background-image:
    repeating-linear-gradient(to bottom, var(--chart-gridline) 0 4px, transparent 4px 8px),
    repeating-linear-gradient(to right, var(--chart-gridline) 0 4px, transparent 4px 8px);
  background-size: 1px 100%, 100% 1px;
  background-position: 50% 0, 0 50%;
  background-repeat: no-repeat, no-repeat;
}

.cl-matrix-quadrant-labels {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.cl-matrix-q-label {
  position: absolute;
  font-size: var(--t-small);
  font-weight: var(--t-body-wt);
  font-style: italic;
  color: var(--report-ink-60);
}

.cl-matrix-dot-wrap {
  position: absolute;
  transform: translate(-50%, 50%);
}

/* Dot size bumped 10px → 14px so it carries comparable visual weight to the
   SVG dot/line charts (which scale up via viewBox); leader 20→24 (per
   Christine, 31 May 2026). */
.cl-matrix-dot {
  width: 14px;
  height: 14px;
  border-radius: var(--radius-full);
  background: var(--gray-mid);
  border: none;
}

/* Per-entity dot colour cycle (positioning-matrix) — 16 colours so up to 16
   competitors get a distinct colour before repeating. Order steps through the
   kicker wheel every-OTHER so consecutive brands get well-separated hues.
   Starts at kicker02 (evens then odds): 02,04,06,08,10,12,14,16,01,03,07,09,11,
   13,15, then kicker05 LAST — starting at 02 keeps the cycle from leading with
   pale kicker01. kicker05 is the user's dot (.leader, set below); putting it last
   keeps it effectively reserved for the user (only a 16th non-user brand would
   reuse it). The first nth-child slot is .cl-matrix-quadrant-labels, so dot-wraps
   start at child #2 — hence the +1 offset vs the legend swatch cycle.
   (Christine, 31 May 2026. Was: started at kicker01 — 01,03,07,09,11,13,15,02…16,05.) */
.cl-matrix-dot-wrap:nth-child(16n+2)   .cl-matrix-dot { background: var(--kicker02); }
.cl-matrix-dot-wrap:nth-child(16n+3)   .cl-matrix-dot { background: var(--kicker04); }
.cl-matrix-dot-wrap:nth-child(16n+4)   .cl-matrix-dot { background: var(--kicker06); }
.cl-matrix-dot-wrap:nth-child(16n+5)   .cl-matrix-dot { background: var(--kicker08); }
.cl-matrix-dot-wrap:nth-child(16n+6)   .cl-matrix-dot { background: var(--kicker10); }
.cl-matrix-dot-wrap:nth-child(16n+7)   .cl-matrix-dot { background: var(--kicker12); }
.cl-matrix-dot-wrap:nth-child(16n+8)   .cl-matrix-dot { background: var(--kicker14); }
.cl-matrix-dot-wrap:nth-child(16n+9)   .cl-matrix-dot { background: var(--kicker16); }
.cl-matrix-dot-wrap:nth-child(16n+10)  .cl-matrix-dot { background: var(--kicker01); }
.cl-matrix-dot-wrap:nth-child(16n+11)  .cl-matrix-dot { background: var(--kicker03); }
.cl-matrix-dot-wrap:nth-child(16n+12)  .cl-matrix-dot { background: var(--kicker07); }
.cl-matrix-dot-wrap:nth-child(16n+13)  .cl-matrix-dot { background: var(--kicker09); }
.cl-matrix-dot-wrap:nth-child(16n+14)  .cl-matrix-dot { background: var(--kicker11); }
.cl-matrix-dot-wrap:nth-child(16n+15)  .cl-matrix-dot { background: var(--kicker13); }
.cl-matrix-dot-wrap:nth-child(16n+16)  .cl-matrix-dot { background: var(--kicker15); }
.cl-matrix-dot-wrap:nth-child(16n+1)   .cl-matrix-dot { background: var(--kicker05); }

/* User's dot = kicker05. Solid centre matches the other dots (14px); it's
   distinguished instead by a 30%-opacity cyan halo ring so "you are here" reads
   at a glance (per Christine, 31 May 2026). Was: 24px centre + 20% halo. */
.cl-matrix-dot-wrap .cl-matrix-dot.leader {
  width: 14px;
  height: 14px;
  background: var(--kicker05);
  border: none;
  box-shadow: 0 0 0 6px color-mix(in srgb, var(--kicker05) 30%, transparent);
}

.cl-matrix-dot-label {
  position: absolute;
  top: -22px;
  left: 50%;
  transform: translateX(-50%);
  font-size: 11px;
  font-weight: var(--t-body-wt);
  color: var(--chart-name-color);
  white-space: nowrap;
}

.cl-matrix-dot-label.leader { color: var(--chart-name-hl-color); font-weight: var(--chart-name-hl-wt); }

/* Bubble-matrix user label — rendered as an HTML overlay (not SVG <text>) so it
   stays a fixed 11px on screen at any chart width, identical to the positioning
   label above (.cl-matrix-dot-label.leader). The SVG label scaled with the chart
   width and read larger than positioning's CSS-px label; this keeps the two
   matrices' user labels consistent. (Christine, 31 May 2026.)
   .bm-label-layer sits directly over the SVG (same width + 640/320 aspect ratio)
   so the inline left/top %s map 1:1 onto the plot; the <svg> stays a direct child
   of .cl-matrix-wrap so the :has(> svg) scoping hook is untouched. */
.bm-label-layer {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  aspect-ratio: 640 / 320; /* mirrors the SVG viewBox (W=640 H=320) */
  pointer-events: none;
  overflow: hidden;
}

.bm-dot-label {
  position: absolute;
  transform: translate(-50%, calc(-100% - 4px)); /* centered above the bubble, 4px gap */
  font-size: 11px; /* small label, matches the positioning leader label (was briefly 14px) */
  font-weight: var(--chart-name-hl-wt);
  color: var(--chart-name-hl-color);
  white-space: nowrap;
  pointer-events: none;
}

.cl-matrix-gap-note {
  font-size: var(--t-small);
  color: var(--report-ink);
  margin-top: var(--spacing-2);
  font-style: italic;
}

.cl-matrix-x-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding-top: var(--spacing-1);
}

.cl-matrix-x-low,
.cl-matrix-x-high {
  font-size: var(--t-small);
  font-weight: var(--font-weight-medium);
  color: var(--report-ink);
}

.cl-matrix-x-label {
  font-size: var(--t-small);
  font-weight: var(--t-body-wt);
  color: var(--report-ink);
}

.cl-matrix-descriptor {
  margin-top: var(--spacing-4);
  border-top: 1px solid var(--report-border);
  padding-top: var(--spacing-4);
}

.cl-matrix-descriptor-title {
  font-size: var(--chart-heading-size);
  font-weight: var(--chart-heading-wt);
  color: var(--chart-heading-color);
  margin-bottom: var(--spacing-2);
}

.cl-matrix-descriptor-body {
  font-size: var(--t-small);
  font-weight: var(--font-weight-light);
  color: var(--report-ink);
  line-height: 1.65;
}

.cl-matrix-chart { width: 100%; }


/* ═══════════════════════════════════════════════════════════════════════════
   DISRUPTION QUADRANT CHART
   AI/disruption probability-impact matrix with scored entities.
   ═══════════════════════════════════════════════════════════════════════════ */

.dq-wrap {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-6);
}

.dq-descriptor {
  border-top: 1px solid var(--report-border);
  padding-top: var(--spacing-4);
}

.dq-score-label {
  font-size: var(--t-small);
  font-weight: var(--font-weight-medium);
  color: var(--report-ink);
  letter-spacing: 0.06em;
  margin-bottom: var(--spacing-1);
}

.dq-score-value {
  font-size: 32px;
  font-weight: var(--font-weight-medium);
  font-variant-numeric: tabular-nums;
  color: var(--report-ink);
  line-height: 1;
  margin-bottom: var(--spacing-2);
}

.dq-score-evidence {
  font-size: var(--t-small);
  font-weight: var(--font-weight-light);
  color: var(--report-ink);
  line-height: 1.65;
}

.dq-matrix-wrap {
  position: relative;
  width: 100%;
}

.dq-matrix-grid {
  display: grid;
  grid-template-columns: 24px 1fr;
  gap: 0;
}

.dq-y-axis {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  padding: var(--spacing-2) 0;
}

.dq-y-label {
  font-size: var(--t-small);
  font-weight: var(--font-weight-medium);
  color: var(--report-ink);
  writing-mode: vertical-rl;
  text-orientation: mixed;
  transform: rotate(180deg);
  white-space: nowrap;
  letter-spacing: 0.06em;
}

.dq-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 1fr 1fr;
  border: 1px solid var(--report-border);
  min-height: 280px;
  position: relative;
}

.dq-row {
  display: contents;
}

.dq-cell {
  padding: var(--spacing-4);
  position: relative;
  min-height: 120px;
}

.dq-cell.top-left    { border-right: 1px solid var(--report-border); border-bottom: 1px solid var(--report-border); }
.dq-cell.top-right   { border-bottom: 1px solid var(--report-border); }
.dq-cell.bottom-left { border-right: 1px solid var(--report-border); }
.dq-cell.bottom-right { }

.dq-cell.active {
  background: var(--gray-background);
}

.dq-cell-name {
  font-size: var(--t-small);
  font-weight: var(--font-weight-medium);
  color: var(--report-ink);
  letter-spacing: 0.06em;
  margin-bottom: var(--spacing-2);
}

.dq-cell.active .dq-cell-name { color: var(--cyan); }

.dq-cell-desc {
  font-size: var(--t-small);
  font-weight: var(--font-weight-light);
  color: var(--report-ink);
  line-height: 1.6;
}

.dq-dot-wrap {
  position: absolute;
  transform: translate(-50%, 50%);
}

.dq-dot {
  width: 10px;
  height: 10px;
  border-radius: var(--radius-full);
  background: var(--report-ink);
}

.dq-dot-label {
  position: absolute;
  top: -18px;
  left: 50%;
  transform: translateX(-50%);
  font-size: var(--t-small);
  font-weight: var(--font-weight-medium);
  color: var(--report-ink);
  white-space: nowrap;
}

.dq-trajectory-label {
  font-size: var(--t-small);
  font-weight: var(--font-weight-medium);
  color: var(--report-ink);
  letter-spacing: 0.04em;
}

.dq-x-axis-wrap {
  display: flex;
  justify-content: space-between;
  padding-top: var(--spacing-1);
  padding-left: 24px;
}

.dq-x-label {
  font-size: var(--t-small);
  font-weight: var(--font-weight-medium);
  color: var(--report-ink);
  letter-spacing: 0.06em;
}


/* ═══════════════════════════════════════════════════════════════════════════
   REPORT CONTEXT OVERRIDES
   When report renders inside the Ren chat split-screen panel.
   ═══════════════════════════════════════════════════════════════════════════ */

.report-container .mi-section        { max-width: 800px; padding-left: 0; padding-right: 0; }
.report-container .mi-sources-section { max-width: none; }
.report-container .mi-divider         { width: 600px; }
.report-container .rpt-action-bar     { max-width: 800px; margin: 0; padding-left: 22px; padding-right: 0; }
.report-container .rpt-toc-drawer     { max-width: 100%; padding-left: var(--report-pad); }
.report-container .rpt-toc-drawer.open { padding-left: var(--report-pad); }
.report-container .rpt-sidebar-col    { display: none; }
.report-container .rpt-about-float-wrap { margin-left: 0; }
.report-container .mi-matrix          { display: block; overflow-x: auto; -webkit-overflow-scrolling: touch; }
.report-container .mi-timeline-cols   { gap: var(--spacing-2); }

@media (max-width: 800px) {
  /* Capital cards stack vertically on mobile everywhere they appear
     (report pages and the chart gallery preview) — the .report-container
     scope was dropping the rule in the gallery. */
  .mi-capital-grid                    { grid-template-columns: 1fr; }
  /* Revert the C4 single-grid (rows display:contents) back to the per-row
     grid on mobile so the existing 1fr/1fr/1fr stack below applies. */
  .report-container .mi-hbar-c4                  { display: block; }
  .report-container .mi-hbar-c4 > .mi-hbar-row   { display: grid; }
  .report-container .mi-hbar-row      { grid-template-columns: 1fr 1fr 1fr; }
  .report-container .mi-dot-row       { grid-template-columns: 130px 1fr 140px; }
  .report-container .mi-dot-axis-labels { grid-template-columns: 130px 1fr 140px; }
  .report-container .mi-twobar-row    { grid-template-columns: 1fr 1fr 1fr; }
}


/* ═══════════════════════════════════════════════════════════════════════════
   STACKED TIMELINE  (screen only — print always keeps the horizontal layout)
   Two triggers:
     A) .mi-timeline-wrap--stack class — applied by template when events > 8
     B) viewport ≤ 640px — stacks all timelines on narrow screens
   Both sets of rules are inside @media screen so @media print is unaffected.

   Geometry (class trigger, same for media trigger):
     .mi-timeline-cols: padding-left 40px; axis ::before at left 19px (centre 20px)
     .mi-timeline-col:  display block; no extra padding (cols' padding gives clearance)
     .mi-timeline-dot:  left -20px; top 20px; transform translate(-50%,-50%)
                        → centre at 40−20 = 20px from cols outer-left (on axis) ✓
   ═══════════════════════════════════════════════════════════════════════════ */

@media screen {

  /* 1 — hide horizontal axis ──────────────────────────────────────────────── */
  .mi-timeline-wrap--stack .mi-timeline-axis { display: none; }

  /* 2 — cols: vertical flex, left border = vertical axis ─────────────────── */
  .mi-timeline-wrap--stack .mi-timeline-cols {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-3);
    padding-left: 40px;
    position: relative;
  }
  .mi-timeline-wrap--stack .mi-timeline-cols::before {
    content: '';
    position: absolute;
    left: 19px;
    top: 6px;
    bottom: 6px;
    width: 1px;
    background: var(--report-border);
    z-index: 0;
  }

  /* 3 — each col: block flow, clear stagger ──────────────────────────────── */
  .mi-timeline-wrap--stack .mi-timeline-col,
  .mi-timeline-wrap--stack .mi-timeline-col:nth-child(4n+2),
  .mi-timeline-wrap--stack .mi-timeline-col:nth-child(4n+3) {
    display: block;
    position: relative;
    --tl-stem: 0px;   /* zeroes the stagger margins (margin-top/bottom use this) */
  }

  /* 4 — ghost cards: suppress entirely (no space reservation needed) ───────── */
  .mi-timeline-wrap--stack .mi-timeline-card--ghost { display: none; }

  /* 5 — stems: vertical axis replaces them ───────────────────────────────── */
  .mi-timeline-wrap--stack .mi-timeline-stem { display: none; }

  /* 6 — dot: pinned to vertical axis, aligned with date text ─────────────── */
  .mi-timeline-wrap--stack .mi-timeline-dot,
  .mi-timeline-wrap--stack .mi-timeline-col.above .mi-timeline-dot,
  .mi-timeline-wrap--stack .mi-timeline-col.below .mi-timeline-dot {
    position: absolute;
    left: -20px;   /* 40px cols-padding − 20px = 20px from cols outer-left = axis */
    top: 20px;     /* aligns with date text (14px card-padding + ~half date line) */
    width: 14px;
    height: 14px;
    transform: translate(-50%, -50%);
    z-index: 1;
  }

  /* 7 — cards: full-width, left-aligned ──────────────────────────────────── */
  .mi-timeline-wrap--stack .mi-timeline-card {
    width: 100%;
    text-align: left;
    align-items: flex-start;
  }
  /* Reset grid-specific placement (no-op in block context, explicit for safety) */
  .mi-timeline-wrap--stack .mi-timeline-col.above > .mi-timeline-card:not(.mi-timeline-card--ghost),
  .mi-timeline-wrap--stack .mi-timeline-col.below > .mi-timeline-card:not(.mi-timeline-card--ghost) {
    grid-row: auto;
    align-self: auto;
    justify-self: auto;
    margin-top: 0;
    margin-bottom: 0;
  }

  /* 8 — no card borders: dot + date carry the per-event accent ──────────── */
  .mi-timeline-wrap--stack .mi-timeline-card {
    border: none;
    background: transparent;
  }
  /* hl dot: larger to mark the pivot/crossover event ─────────────────────── */
  .mi-timeline-wrap--stack .mi-timeline-dot.hl {
    width: 18px;
    height: 18px;
  }

  /* 9 — sequential kicker colours: dot fill + date text (kicker03→kicker12)
     Same ramp used by decision-journey. Dot colour is the event's identity;
     date text echoes it so the event reads as a coloured unit, not a plain row.
     hl flag still controls size (rule 8 above); colour follows the slot.        */
  .mi-timeline-wrap--stack .mi-timeline-col:nth-child(1)  .mi-timeline-dot { background: var(--kicker03); }
  .mi-timeline-wrap--stack .mi-timeline-col:nth-child(1)  .mi-timeline-card-date { color: var(--kicker03); }
  .mi-timeline-wrap--stack .mi-timeline-col:nth-child(2)  .mi-timeline-dot { background: var(--kicker04); }
  .mi-timeline-wrap--stack .mi-timeline-col:nth-child(2)  .mi-timeline-card-date { color: var(--kicker04); }
  .mi-timeline-wrap--stack .mi-timeline-col:nth-child(3)  .mi-timeline-dot { background: var(--kicker05); }
  .mi-timeline-wrap--stack .mi-timeline-col:nth-child(3)  .mi-timeline-card-date { color: var(--kicker05); }
  .mi-timeline-wrap--stack .mi-timeline-col:nth-child(4)  .mi-timeline-dot { background: var(--kicker06); }
  .mi-timeline-wrap--stack .mi-timeline-col:nth-child(4)  .mi-timeline-card-date { color: var(--kicker06); }
  .mi-timeline-wrap--stack .mi-timeline-col:nth-child(5)  .mi-timeline-dot { background: var(--kicker07); }
  .mi-timeline-wrap--stack .mi-timeline-col:nth-child(5)  .mi-timeline-card-date { color: var(--kicker07); }
  .mi-timeline-wrap--stack .mi-timeline-col:nth-child(6)  .mi-timeline-dot { background: var(--kicker08); }
  .mi-timeline-wrap--stack .mi-timeline-col:nth-child(6)  .mi-timeline-card-date { color: var(--kicker08); }
  .mi-timeline-wrap--stack .mi-timeline-col:nth-child(7)  .mi-timeline-dot { background: var(--kicker09); }
  .mi-timeline-wrap--stack .mi-timeline-col:nth-child(7)  .mi-timeline-card-date { color: var(--kicker09); }
  .mi-timeline-wrap--stack .mi-timeline-col:nth-child(8)  .mi-timeline-dot { background: var(--kicker10); }
  .mi-timeline-wrap--stack .mi-timeline-col:nth-child(8)  .mi-timeline-card-date { color: var(--kicker10); }
  .mi-timeline-wrap--stack .mi-timeline-col:nth-child(9)  .mi-timeline-dot { background: var(--kicker11); }
  .mi-timeline-wrap--stack .mi-timeline-col:nth-child(9)  .mi-timeline-card-date { color: var(--kicker11); }
  .mi-timeline-wrap--stack .mi-timeline-col:nth-child(10) .mi-timeline-dot { background: var(--kicker12); }
  .mi-timeline-wrap--stack .mi-timeline-col:nth-child(10) .mi-timeline-card-date { color: var(--kicker12); }

}

/* ── Viewport ≤ 640px: identical stacked layout for every timeline ─────── */
@media screen and (max-width: 640px) {
  .mi-timeline-wrap .mi-timeline-axis { display: none; }

  .mi-timeline-wrap .mi-timeline-cols {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-3);
    padding-left: 24px;
    position: relative;
  }
  .mi-timeline-wrap .mi-timeline-cols::before {
    content: '';
    position: absolute;
    left: 9px;
    top: 6px;
    bottom: 6px;
    width: 1px;
    background: var(--report-border);
    z-index: 0;
  }
  .mi-timeline-wrap .mi-timeline-col,
  .mi-timeline-wrap .mi-timeline-col:nth-child(4n+2),
  .mi-timeline-wrap .mi-timeline-col:nth-child(4n+3) {
    display: block;
    position: relative;
    --tl-stem: 0px;
  }
  .mi-timeline-wrap .mi-timeline-card--ghost { display: none; }
  .mi-timeline-wrap .mi-timeline-stem { display: none; }
  .mi-timeline-wrap .mi-timeline-dot,
  .mi-timeline-wrap .mi-timeline-col.above .mi-timeline-dot,
  .mi-timeline-wrap .mi-timeline-col.below .mi-timeline-dot {
    position: absolute;
    left: -14px;
    top: 20px;
    transform: translate(-50%, -50%);
    z-index: 1;
  }
  .mi-timeline-wrap .mi-timeline-card {
    width: 100%;
    text-align: left;
    align-items: flex-start;
  }
  .mi-timeline-wrap .mi-timeline-col.above > .mi-timeline-card:not(.mi-timeline-card--ghost),
  .mi-timeline-wrap .mi-timeline-col.below > .mi-timeline-card:not(.mi-timeline-card--ghost) {
    grid-row: auto;
    align-self: auto;
    justify-self: auto;
    margin-top: 0;
    margin-bottom: 0;
  }
}


/* ═══════════════════════════════════════════════════════════════════════════
   PRINT OVERRIDES
   ═══════════════════════════════════════════════════════════════════════════ */

@media print {
  .mi-capital-card,
  .mi-timeline-card,
  .mi-scenario-row-item,
  .mi-stat-callout { break-inside: avoid; }

  /* ── Research-report break protections — specificity fix ──────────────────
     The free-flow reset in components.css uses
     `.sim-v2.rpt-card-stack .mi-section *` (0,3,0) !important, which
     silently overrides any protection at lower specificity.  The three
     selectors below and the finding-card grid block are re-scoped to
     (0,4,0)/(0,4,1) so they always beat the reset.
     Screen output is unaffected — all rules are inside @media print.   */

  /* Intel list rows and stat callouts inside research sections */
  .sim-v2.rpt-card-stack .mi-section .mi-intel-item,
  .sim-v2.rpt-card-stack .mi-section .mi-stat-callout,
  .sim-v2.rpt-card-stack .mi-section .mi-key-findings li {
    break-inside: avoid !important;
  }

  /* Grid-variant finding cards: collapse to single-column so each card is a
     full-width block element — break-inside:avoid is reliable on block items
     but not on same-row grid items in Chromium's print engine.
     Selector specificity (0,4,1) beats the (0,3,0) free-flow reset. */
  .sim-v2.rpt-card-stack .mi-section .mi-key-findings--grid {
    display: block;
  }
  .sim-v2.rpt-card-stack .mi-section .mi-key-findings--grid li {
    break-inside: avoid !important;
    page-break-inside: avoid !important;
    margin-bottom: var(--spacing-4);
  }
  .sim-v2.rpt-card-stack .mi-section .mi-key-findings--grid li:last-child {
    margin-bottom: 0;
  }

  /* Remove bar border from horizontal-bar fills in print — the 1px
     report-border outline is invisible on screen for .hl/.dim (already
     border:none) but shows on the base fill; strip it for a clean PDF. */
  .mi-hbar-fill { border: none; }

  .mi-capital-card.hl,
  .mi-timeline-card.hl,
  .mi-analyst,
  .mi-hbar-fill.hl,
  .mi-dot-circle.hl,
  .mi-seg-segment.hl,
  .mi-twobar-fill.hl,
  .mi-timeline-dot.hl,
  .mi-scenario-sq.hl,
  .mi-scenario-sq.on,
  .mi-heatmap .heat-3,
  .mi-heatmap .heat-4,
  .mi-heatmap .heat-5,
  .mi-heatmap .heat-hl,
  .mi-line-series.hl,
  .mi-line-dot.hl {
    -webkit-print-color-adjust: exact !important;
    print-color-adjust: exact !important;
  }

  .mi-divider { display: none; }

  /* Timeline print: 180px fixed-width cards, 20px stem offset.
     Above cards left-anchored, below cards right-anchored via negative margin.
     Cards overflow their ~93px tracks horizontally but alternate above/below
     so there is no vertical clash. */
  .mi-timeline-wrap { overflow-x: visible; }
  /* Flatten the 4-cycle stem stagger (screen: 30px/100px alternating).
     The nth-child rules have specificity 0,2,0 — match that here to win. */
  .mi-timeline-col              { --tl-stem: 20px; }
  .mi-timeline-col:nth-child(4n+2),
  .mi-timeline-col:nth-child(4n+3) { --tl-stem: 100px; }
  /* Both rows 180px. Above: left-anchored, dot at 90px (card centre).
     Below: right-anchored via negative margin, dot at calc(100% - 90px). */
  .mi-timeline-card {
    border: 1.5px solid var(--navy);
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }
  .mi-timeline-col.above > .mi-timeline-card { width: 180px; }
  .mi-timeline-col.above .mi-timeline-stem,
  .mi-timeline-col.above .mi-timeline-dot { left: 90px; }
  .mi-timeline-col.below > .mi-timeline-card {
    width: 180px;
    justify-self: start;
    margin-left: calc(100% - 180px);
  }
  .mi-timeline-col.below .mi-timeline-stem,
  .mi-timeline-col.below .mi-timeline-dot { left: calc(100% - 90px); }

  /* Stack timeline print — override horizontal rules above so .mi-timeline-wrap--stack
     renders as a vertical list in PDF exactly as it does on screen.
     Selectors are scoped to .mi-timeline-wrap--stack so non-stack timelines keep
     the horizontal print layout. */
  .mi-timeline-wrap--stack .mi-timeline-axis { display: none; }

  .mi-timeline-wrap--stack .mi-timeline-cols {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-3);
    padding-left: 40px;
    position: relative;
    overflow-x: visible;
  }
  .mi-timeline-wrap--stack .mi-timeline-cols::before {
    content: '';
    position: absolute;
    left: 19px; top: 6px; bottom: 6px;
    width: 2px;
    background: var(--navy);
    z-index: 0;
  }

  /* Each col: block flow, clear the stagger variable */
  .mi-timeline-wrap--stack .mi-timeline-col,
  .mi-timeline-wrap--stack .mi-timeline-col:nth-child(4n+2),
  .mi-timeline-wrap--stack .mi-timeline-col:nth-child(4n+3) {
    display: block;
    position: relative;
    --tl-stem: 0px;
  }

  /* Ghost cards and stems not needed in vertical layout */
  .mi-timeline-wrap--stack .mi-timeline-card--ghost { display: none; }
  .mi-timeline-wrap--stack .mi-timeline-stem { display: none; }

  /* Dot: pin to the vertical axis */
  .mi-timeline-wrap--stack .mi-timeline-dot,
  .mi-timeline-wrap--stack .mi-timeline-col.above .mi-timeline-dot,
  .mi-timeline-wrap--stack .mi-timeline-col.below .mi-timeline-dot {
    position: absolute;
    left: -20px; top: 20px;
    width: 14px; height: 14px;
    transform: translate(-50%, -50%);
    z-index: 1;
    -webkit-print-color-adjust: exact !important;
    print-color-adjust: exact !important;
  }

  /* Cards: full-width, reset the horizontal 180px/margin rules */
  .mi-timeline-wrap--stack .mi-timeline-card,
  .mi-timeline-wrap--stack .mi-timeline-col.above > .mi-timeline-card,
  .mi-timeline-wrap--stack .mi-timeline-col.below > .mi-timeline-card {
    width: 100%;
    justify-self: auto;
    margin-left: 0;
    text-align: left;
    align-items: flex-start;
    border: none;
    background: transparent;
  }

  /* Stems/dots: override the horizontal left offsets */
  .mi-timeline-wrap--stack .mi-timeline-col.above .mi-timeline-stem,
  .mi-timeline-wrap--stack .mi-timeline-col.above .mi-timeline-dot,
  .mi-timeline-wrap--stack .mi-timeline-col.below .mi-timeline-stem,
  .mi-timeline-wrap--stack .mi-timeline-col.below .mi-timeline-dot {
    left: -20px;
  }

  /* Sequential kicker colours — mirror the @media screen ramp so PDF dots
     and date labels carry the same palette as the screen render */
  .mi-timeline-wrap--stack .mi-timeline-col:nth-child(1)  .mi-timeline-dot { background: var(--kicker03) !important; }
  .mi-timeline-wrap--stack .mi-timeline-col:nth-child(1)  .mi-timeline-card-date { color: var(--kicker03); }
  .mi-timeline-wrap--stack .mi-timeline-col:nth-child(2)  .mi-timeline-dot { background: var(--kicker04) !important; }
  .mi-timeline-wrap--stack .mi-timeline-col:nth-child(2)  .mi-timeline-card-date { color: var(--kicker04); }
  .mi-timeline-wrap--stack .mi-timeline-col:nth-child(3)  .mi-timeline-dot { background: var(--kicker05) !important; }
  .mi-timeline-wrap--stack .mi-timeline-col:nth-child(3)  .mi-timeline-card-date { color: var(--kicker05); }
  .mi-timeline-wrap--stack .mi-timeline-col:nth-child(4)  .mi-timeline-dot { background: var(--kicker06) !important; }
  .mi-timeline-wrap--stack .mi-timeline-col:nth-child(4)  .mi-timeline-card-date { color: var(--kicker06); }
  .mi-timeline-wrap--stack .mi-timeline-col:nth-child(5)  .mi-timeline-dot { background: var(--kicker07) !important; }
  .mi-timeline-wrap--stack .mi-timeline-col:nth-child(5)  .mi-timeline-card-date { color: var(--kicker07); }
  .mi-timeline-wrap--stack .mi-timeline-col:nth-child(6)  .mi-timeline-dot { background: var(--kicker08) !important; }
  .mi-timeline-wrap--stack .mi-timeline-col:nth-child(6)  .mi-timeline-card-date { color: var(--kicker08); }
  .mi-timeline-wrap--stack .mi-timeline-col:nth-child(7)  .mi-timeline-dot { background: var(--kicker09) !important; }
  .mi-timeline-wrap--stack .mi-timeline-col:nth-child(7)  .mi-timeline-card-date { color: var(--kicker09); }
  .mi-timeline-wrap--stack .mi-timeline-col:nth-child(8)  .mi-timeline-dot { background: var(--kicker10) !important; }
  .mi-timeline-wrap--stack .mi-timeline-col:nth-child(8)  .mi-timeline-card-date { color: var(--kicker10); }
  .mi-timeline-wrap--stack .mi-timeline-col:nth-child(9)  .mi-timeline-dot { background: var(--kicker11) !important; }
  .mi-timeline-wrap--stack .mi-timeline-col:nth-child(9)  .mi-timeline-card-date { color: var(--kicker11); }
  .mi-timeline-wrap--stack .mi-timeline-col:nth-child(10) .mi-timeline-dot { background: var(--kicker12) !important; }
  .mi-timeline-wrap--stack .mi-timeline-col:nth-child(10) .mi-timeline-card-date { color: var(--kicker12); }
}


/* ═══════════════════════════════════════════════════════════════════════════
   NAMING CONVENTION — DO NOT VIOLATE
   ─────────────────────────────────────────────────────────────────────────
   All classes in this file must use a component-based prefix, never a
   report slug prefix.

   CORRECT:   .mi-hbar-*      (describes: horizontal bar chart)
   CORRECT:   .cl-matrix-*    (describes: competitive/quadrant matrix)
   CORRECT:   .dq-grid        (describes: disruption quadrant grid)
   WRONG:     .market-intel-* (report slug as prefix — banned)
   WRONG:     .comp-land-*    (report slug as prefix — banned)

   Before adding a new class: check components.css for the same component.
   Never duplicate a class across both files.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── C4 mobile two-row layout ────────────────────────────────────────────────
   Desktop shared grid (display:grid, col-1=max-content) makes the label
   column as wide as the longest label, leaving almost no room for bars on
   a phone. On mobile: stack rows vertically, label full-width on row 1,
   bar + stat side-by-side on row 2. Same-file placement beats !important. */
@media (max-width: 767px) {
  .mi-hbar-chart,
  .mi-hbar-c4 {
    display: flex;
    flex-direction: column;
    width: 100%;
    max-width: 100%;
    box-sizing: border-box;
    gap: var(--spacing-3);
  }
  .mi-hbar-c4 > .mi-hbar-row {
    display: grid;
    width: 100%;
    box-sizing: border-box;
    grid-template-columns: 1fr auto;
    grid-template-rows: auto auto;
    row-gap: 5px;
    column-gap: 8px;
    align-items: center;
  }
  .mi-hbar-c4 > .mi-hbar-row .mi-hbar-namecell {
    grid-column: 1 / -1;
    grid-row: 1;
  }
  .mi-hbar-c4 > .mi-hbar-row .mi-hbar-namecell .mi-hbar-label {
    margin-bottom: 0;
  }
  .mi-hbar-c4 > .mi-hbar-row .mi-hbar-track {
    grid-column: 1;
    grid-row: 2;
  }
  .mi-hbar-c4 > .mi-hbar-row .mi-hbar-secondary {
    grid-column: 2;
    grid-row: 2;
    align-self: center;
  }

  /* Waterfall x-axis labels: Chromium PDF reverses characters when text is
     rotated via transform:rotate(-90deg)+transform-origin:top right. Switch
     to writing-mode for a PDF-safe equivalent that renders identically in
     both browser and PDF. */
  .mi-waterfall-label {
    writing-mode: vertical-rl;
    text-orientation: mixed;
    transform: rotate(180deg);
    transform-origin: 50% 50%;
    left: 0;
    right: 0;
    margin: auto;
    width: 1.2em;
    text-align: center !important;
  }

  /* Dim bar fills: --gray-light (#e2e7ed) does not trigger print-color-adjust
     in Chromium and is too pale against white. Darken and force-print so all
     bars (not just the highlighted max-value bar) remain legible in PDF. */
  .mi-hbar-fill.dim,
  .mi-twobar-fill.is-lower {
    -webkit-print-color-adjust: exact !important;
    print-color-adjust: exact !important;
    background: #b8c2cc !important;
  }
}

@media (max-width: 767px) {
  /* Stat callouts — 24px all-round padding on mobile (desktop uses the wider
     container-pad tokens: 28px top/bottom, 35px left/right). */
  .mi-stat-callout { padding: 24px !important; }

  /* Tight legends — reduce row gap and line-height across all chart legend
     families so multi-row legends don't sprawl on mobile. */
  .mi-stacked-legend,
  .mi-hbar-legend,
  .mi-dual-legend { gap: 4px 10px !important; }

  .mi-seg-callouts { gap: 4px 10px !important; }

  /* Hanging indent: second+ lines align with the text start after the dot
     (dot=8px + margin-right=6px = 14px offset, trimmed 2px per visual QA). */
  .mi-seg-callout {
    padding-left: 11px !important;
    text-indent: -11px !important;
  }

  .mi-stacked-legend-item,
  .mi-hbar-legend-item,
  .mi-dual-legend__item,
  .mi-seg-callout { line-height: 1.2 !important; }
}

/* Relocation-plan stat-callout values: these are long prose strings (names,
   dates, destination lists) not short numbers, so 24px wraps badly on mobile.
   Drop to 18px and let line-height breathe a little. Scoped to the product
   so no other report is touched. */
@media (max-width: 767px) {
  .rpt-card-stack[data-product="relocation-plan"] .mi-stat-callout-value {
    font-size: 18px !important;
    line-height: 1.3 !important;
  }
  .rpt-card-stack[data-product="relocation-plan"] .mi-stat-callout-value .rpt-score {
    font-size: 18px !important;
  }
  .rpt-card-stack[data-product="relocation-plan"] .mi-stat-callout-value .rpt-score .sv-score-suffix {
    font-size: 18px !important;
  }
}

/* Partnership evaluation — extra breathing room below the economic-fit
   two-bar chart before the prose blocks card that follows. */
.rpt-card-stack[data-product="partnership-evaluation"] #economic_fit .mi-twobar-chart {
  margin-bottom: 30px;
}



/* Mobile: line-trend overflow fixes.
   1. The rightmost x-axis label overflows the SVG box by a few px via
      overflow:visible → triggers a page-level scrollbar. Clip it on mobile.
   2. The legend swatch is flex-shrink:0 so a long label pushes the row
      wider than the card. Allow wrapping + let the label compress. */
@media (max-width: 767px) {
  .mi-line-trend {
    overflow: hidden;
  }
  .mi-line-legend {
    flex-wrap: wrap;
  }
  .mi-line-legend-label {
    min-width: 0;
  }
}
