/* PORTED VERBATIM from vo-app-marketing-hub/apps/Marketing-Hub/marketing-hub-performance.css, minus 4 rule(s)
   whose selectors name a class crm.css / ax-containers.css already own.
   DO NOT EDIT — node tools/port-marketing-hub.cjs */
/* ══════════════════════════════════════════════════════════════════════════
   marketing-hub-performance.css — the Performance (Reports) tab.

   ⚠️ ALMOST NOTHING BELONGS IN THIS FILE, ON PURPOSE.

   The page is the Work app's Reports hub, so work.css owns the frame
   (.wk-tab-picker, .ax-cards-row, .ax-card, .wk-body, .wk-focus-panel,
   .wk-focus-head, .wk-support-stack, .rp-card, .rp-card-stats, .wk-empty) and
   marketing-hub-home.css owns the shared list/card furniture it already
   vendored from Training Materials (.tmr-thumb, .tmr-prev, .tmr-badges,
   .mh-viewtog, .mh-rail-row, .mh-src-down, .mh-mailshot, .mh-home-empty).

   ⚠️ The list and grid containers deliberately carry Home's `.mh-home-list` /
   `.mh-home-grid` / `.mh-home-view` classes as well as their own. Those three
   rules are the row-sizing the Training Materials block depends on, and
   sharing the class is the only way the two hubs' lists cannot drift apart.
   Re-styling them here would fork the look — feedback_ported_file_features_
   go_upstream. Do not.

   What IS this file's own: the period bar's segmented control, the metric
   strip a report row carries, the source tags, and the channel row.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── The period bar. work.css's .wk-tab-picker is the shell; the control
      inside it is segmented rather than a dropdown because three fixed
      windows do not deserve a menu (and a menu inside the panel would be
      clipped, which is why the bar sits outside it in the first place). ── */
#mhPerfWindow { display: inline-flex; gap: 2px; padding: 3px; flex-shrink: 0;
  background: var(--surf-2, #f1f5f9); border: 1px solid var(--border, #e2e8f0); border-radius: 9px; }

#mhPerfWindow button {
  border: 0; background: transparent; cursor: pointer;
  font-size: 11.5px; font-weight: 600; color: var(--ink3, #64748b);
  padding: 5px 12px; border-radius: 7px; white-space: nowrap;
  transition: background .15s, color .15s;
}

#mhPerfWindow button:hover { color: var(--ink, #0f172a); }

.mhp-picker-spacer { flex: 1 1 auto; }

.mhp-period-note { font-size: 11px; color: var(--ink4, #94a3b8); white-space: nowrap; }

/* ── The report row. `.ax-triage-row.tmr-row` supplies the shell; these are
      the two things a PERFORMANCE row has that a pipeline row does not: a
      tag line saying where it came from, and a strip of what it earned. ── */
.mhp-row-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 4px; }

.mhp-badges { align-self: center; }

.mhp-tags { display: flex; flex-wrap: wrap; gap: 4px; align-items: center; }

.mhp-tag {
  font-size: 8.5px; font-weight: 700; line-height: 1.5;
  padding: 1px 7px; border-radius: 4px;
  text-transform: uppercase; letter-spacing: .4px; white-space: nowrap;
  max-width: 180px; overflow: hidden; text-overflow: ellipsis;
}

/* The template tag is the answer to "where did this come from" — it reads as
   a provenance label, not as another status pill, so it is outlined. */
.mhp-tag--tpl {
  background: transparent; color: var(--ink3, #64748b);
  border: 1px dashed var(--border, #cbd5e1); text-transform: none; letter-spacing: 0;
  font-weight: 600; font-size: 9px;
}

.mhp-tag--acct { background: rgba(100, 116, 139, .12); color: var(--ink3, #64748b);
  text-transform: none; letter-spacing: 0; font-weight: 600; font-size: 9px; }

.mhp-tag--free { background: rgba(148, 163, 184, .16); color: var(--ink3, #64748b);
  text-transform: none; letter-spacing: 0; font-weight: 600; font-size: 9px; }

/* A tag that came off the CRM record rather than off the send — `email-bounce`,
   `marketing:suppressed`, `departed-auto`. Dotted rather than filled so it
   reads as a different KIND of fact from the event tags beside it: those say
   what happened to this email, these say what we already knew about the person. */
.mhp-tag--crm { background: transparent; color: var(--ink3, #64748b);
  border: 1px dotted rgba(100, 116, 139, .5);
  text-transform: none; letter-spacing: 0; font-weight: 600; font-size: 9px; }

/* ══════════════════════════════════════════════════════════════════════════
   AN ACCOUNT THAT HAS GONE DARK, AND THE PEOPLE IT WENT DARK THROUGH.

   Tyler, 2026-08-13: *"That list just looks so bad. The design looks so bad.
   Are you trying to do the companies? Really show the people."*

   It was right: the row carried a name, one pill and one sentence in a shell
   built for a send with a thumbnail and a metrics strip, so two thirds of it
   was empty space and the interesting part — WHO — was not on it at all. The
   evidence now sits under the name as its own block.

   ⚠️ A LIST INSIDE A ROW, NOT A NESTED ROW. It must not pick up
   `.ax-triage-row`'s padding, hover or cursor: the account is the clickable
   thing, and a second hover target inside it reads as a link that does
   nothing.
   ══════════════════════════════════════════════════════════════════════════ */
.mhp-co-lost {
  display: flex; flex-direction: column; gap: 1px;
  margin-top: 5px; padding: 6px 8px 6px 9px;
  border-radius: 7px;
  background: rgba(148, 163, 184, .09);
  /* The account is unreachable BECAUSE of these — the bar ties cause to claim. */
  border-left: 2px solid rgba(220, 38, 38, .35);
}

.mhp-co-lost-row {
  display: flex; align-items: baseline; gap: 7px;
  font-size: 11px; line-height: 1.65; min-width: 0;
}

.mhp-co-dot {
  width: 5px; height: 5px; border-radius: 50%; flex: none;
  transform: translateY(-1px);
}

/* ⚠️ THE ADDRESS IS THE ANSWER, so it is the thing that does not shrink or
   wrap — the name and the verdict give way to it. */
.mhp-co-em {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 10.5px; color: var(--ink2, #475569); font-weight: 600;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 300px;
}

.mhp-co-name {
  color: var(--ink3, #64748b); font-weight: 600;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  flex: 0 1 auto; min-width: 0;
}

/* Pushed right so the verdicts line up as a column and the exceptions —
   "still on the account", "nothing was done" — are scannable down the list. */
.mhp-co-why {
  margin-left: auto; font-weight: 700; font-size: 10px;
  white-space: nowrap; flex: none;
}

/* The headcount, as a badge rather than a sentence — it was competing with the
   account name for the same line. */
.mhp-co-count {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 26px; height: 22px; padding: 0 7px;
  border-radius: 6px; background: rgba(124, 58, 237, .1);
  color: #7c3aed; font-weight: 800; font-size: 12px;
}

@media (max-width: 900px) {
  /* The verdict drops under the address rather than squeezing it. */
  .mhp-co-lost-row { flex-wrap: wrap; }
  .mhp-co-why { margin-left: 0; }
  .mhp-co-em { max-width: 100%; }
}

/* ⚠️ THE SCANNER TAG IS DELIBERATELY DRAB. It is the one tag on the row that
   says "discount everything else here", and a bright one would pull the eye
   toward the rows that matter least. */
.mhp-tag--bot { background: rgba(148, 163, 184, .2); color: #64748b;
  border: 1px solid rgba(148, 163, 184, .45);
  text-transform: none; letter-spacing: 0; font-weight: 700; font-size: 9px; }
/* …and the row it sits on recedes with it, without disappearing: these people
   were really emailed and the address is really valid. */
.mhp-row--who[data-mhp-bot] { opacity: .72; }
.mhp-row--who[data-mhp-bot]:hover { opacity: 1; }

/* ── The metric strip. A chip is one measured fact: the number in ink, the
      unit in grey. Missing metrics are ABSENT, never rendered as zeros, so
      the strip is deliberately not a fixed-width grid — a short strip means
      we measured less, and that should be visible. ── */
.mhp-strip { display: flex; flex-wrap: wrap; gap: 4px 10px; align-items: center; }

.mhp-chip {
  display: inline-flex; align-items: baseline; gap: 4px;
  font-size: 10.5px; color: var(--ink4, #94a3b8); white-space: nowrap;
}

.mhp-chip b { font-size: 11.5px; font-weight: 700; color: var(--ink2, #475569); }

.mhp-chip--bad b { color: #dc2626; }

.mhp-chip--muted { font-style: italic; color: var(--ink4, #94a3b8); }

/* ── The channel row. A channel is not a piece, so instead of a document
      thumbnail it wears its own two-letter mark in its brand colour. ── */
.mhp-chan-mark {
  width: 44px; height: 44px; flex-shrink: 0; border-radius: 10px;
  display: flex; align-items: center; justify-content: center;
  font-size: 17px; font-weight: 800; letter-spacing: 0;
}

.mhp-chan-mark svg { width: 20px; height: 20px; }

.mhp-chan-rate { font-size: 13px; font-weight: 800; letter-spacing: -.01em; }

.mhp-chan-card .rp-card-body { padding-top: 14px; }

/* ── Rail links are real anchors (a clicked URL should open), so they need
      the row's layout without the row's cursor lie. ── */
a.mhp-rail-link { text-decoration: none; color: inherit; }

a.mhp-rail-link:hover .mh-rail-title { color: var(--c-blue, #3b82f6); }

@media (prefers-color-scheme: dark) {
#mhPerfWindow { background: rgba(148, 163, 184, .12); border-color: rgba(148, 163, 184, .22); }

.mhp-tag--tpl { border-color: rgba(148, 163, 184, .35); }
.mhp-tag--crm { border-color: rgba(148, 163, 184, .45); color: #94a3b8; }
.mhp-tag--bot { background: rgba(148, 163, 184, .18); color: #cbd5e1;
  border-color: rgba(148, 163, 184, .4); }
.mhp-row--who[data-mhp-bot] { opacity: .62; }
.mhp-lead-bot { background: rgba(148, 163, 184, .14); color: #cbd5e1;
  border-left-color: rgba(148, 163, 184, .55); }
.mhp-lead-link { color: #38bdf8; }
.mhp-more { background: rgba(148, 163, 184, .12); color: #cbd5e1;
  border-color: rgba(148, 163, 184, .3); }
.mhp-more:hover { background: rgba(148, 163, 184, .22); }
}

/* ══════════════════════════════════════════════════════════════════════
   The picker row now carries Work's .rp-drop controls. Everything visual
   comes from apps/Work/work.css; these rules only place them in this row
   and hide the native date input behind its styled trigger.
   ══════════════════════════════════════════════════════════════════════ */
/* ══ 🚨 THE SELECTED NAME MAY NOT CHANGE THE BAR'S GEOMETRY ═════════════
   Tyler, 2026-08-28: *"when you start filtering and the name gets long, I
   don't want the top to indent."*

   `.rp-drop-val` already ellipsises — but only once something CONSTRAINS it,
   and nothing did. A `.mhp-drop` with no max-width takes its intrinsic width
   from the button's max-content, so picking a piece called "Drive Your Toy
   Event Attendee Registration - Drive Your Toy event reminder and details
   email" made one control 600px wide, pushed the period picker onto a second
   line, and moved every caption and separator on the row. The bar reads as a
   sentence, and a sentence that re-wraps every time you answer part of it is
   the thing that looks broken — not the length of the name.

   So the controls are the same size whatever is selected: the value truncates,
   and the full string is on `title=` where it always was (setTrigger). The
   MENU is `position:absolute` with its own left/right, so capping the trigger
   does not narrow the list you pick from.
   ══════════════════════════════════════════════════════════════════════════ */
/* 🚨 A CAP IS NOT A FIX — MEASURED. With `max-width` alone the piece
   control still went 158px -> 232px, the period picker still slid 74px right
   and the row still wrapped to a second line (69px -> 122px). A control that
   is *sometimes* 158 and *sometimes* 232 is exactly the indent Tyler is
   describing. So the width is FIXED and the label truncates into it: the bar
   is the same shape empty, filtered, and filtered by a 92-character name.
   `flex-shrink: 1` is kept so a narrow viewport can still compress the row
   rather than overflow it — that moves everything at once, which reads as a
   layout and not as a twitch. */
.mhp-drop { flex: 0 1 182px; width: 182px; min-width: 0; }

/* min-width:auto is the flexbox default and it defeats the width above by
   refusing to shrink a nowrap label below its own text. Both levels need it —
   the button is a flex item of .mhp-drop and the value is a flex item of the
   button, and either one left at `auto` re-inflates the control. */
.mhp-drop > .rp-drop-btn { min-width: 0; max-width: 100%; }
.mhp-drop > .rp-drop-btn > .rp-drop-val { min-width: 0; }

.mhp-drop .rp-drop-btn { width: 100%; }

.mhp-custom { display: flex; gap: 6px; align-items: center; }

.mhp-custom .rp-date-trigger { position: relative; min-width: 132px; }

/* The native picker is the control; the styled button is what you see. It
   must stay clickable and cover the trigger, or the calendar never opens. */
.mhp-date-native {
  position: absolute; inset: 0; width: 100%; height: 100%;
  opacity: 0; cursor: pointer; border: 0; padding: 0; margin: 0;
}

.mhp-summary { margin: 0; }

.mhp-summary.is-invalid { color: #dc2626; font-weight: 600; }

/* ══════════════════════════════════════════════════════════════════════
   ONE FILTER BAR
   ══════════════════════════════════════════════════════════════════════
   Tyler, 2026-08-11: *"I don't like that there's a filter for Performance
   and then a filter for Period. It should just have an overall better
   filter design."*

   Before, two strips stacked: the surface picker in one and PERIOD in
   another, both narrowing the same report and neither admitting the other
   existed. This is one card that reads left to right as a sentence — WHICH
   report, then WHAT to narrow it to — with the live filters as chips on a
   second line that only exists when something is filtered.

   ⚠️ THE CONTROLS THEMSELVES ARE STILL WORK'S .rp-drop. Nothing here
   restyles a .rp-drop-btn; these rules lay them out and draw the frame
   around them. Restyle the control and the Work report builder drifts.
   ══════════════════════════════════════════════════════════════════════ */
.mhp-filterbar {
  background: var(--wt-surface, #fff);
  border: 1px solid var(--line, #e2e8f0);
  border-radius: 12px;
  padding: 10px 12px;
  margin-bottom: 14px;
  box-shadow: 0 1px 2px rgba(15, 23, 42, .04);
}

.mhp-fb-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

/* A caption, not a label — it names the group of controls after it. */
.mhp-fb-cap {
  font-size: 10px; font-weight: 700; letter-spacing: .07em; text-transform: uppercase;
  color: var(--ink4, #94a3b8); white-space: nowrap; padding-right: 2px;
}

.mhp-fb-sep {
  width: 1px; align-self: stretch; min-height: 22px;
  background: var(--line, #e2e8f0); margin: 0 4px;
}

/* The report picker leads the bar, so it is the one control that reads as
   primary. Everything after it is a narrowing filter. */
.mhp-drop--surface { flex: 0 1 190px; width: 190px; }

.mhp-drop--surface > .rp-drop-btn { font-weight: 650; }

.mhp-picker-spacer { flex: 1 1 auto; min-width: 8px; }

/* ── Two-line options. A list of sends is full of near-identical names, so
      the channel and the date carry the choice, not the title alone. ── */
.mhp-opt-2line { display: flex; flex-direction: column; gap: 1px; line-height: 1.25; }

.mhp-opt-main { font-weight: 600; }

.mhp-opt-sub { font-size: 10.5px; color: var(--ink4, #94a3b8); }

.mhp-opt-dot {
  display: inline-block; width: 7px; height: 7px; border-radius: 50%;
  margin-right: 7px; vertical-align: middle; flex: 0 0 auto;
}

/* ── THE CHIP ROW ────────────────────────────────────────────────────
      Every number on the page is computed under these, so they are the
      caption for the whole screen. `hidden` is honoured explicitly because
      an author `display:flex` beats the attribute otherwise — the trap
      reference_hidden_attr_loses_to_author_display records. ── */
.mhp-fb-chips {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  margin-top: 9px; padding-top: 9px;
  border-top: 1px dashed var(--line, #e2e8f0);
}

.mhp-fb-chips[hidden] { display: none; }

.mhp-chip-f {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 6px 4px 8px; border-radius: 999px;
  border: 1px solid var(--line, #e2e8f0);
  background: var(--wt-page-bg, #f8fafc);
  font: inherit; font-size: 11px; cursor: pointer; max-width: 300px;
}

.mhp-chip-f:hover { border-color: #dc2626; color: #dc2626; }

.mhp-chip-f-cap {
  font-size: 9.5px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase;
  color: var(--ink4, #94a3b8);
}

.mhp-chip-f:hover .mhp-chip-f-cap { color: inherit; }

.mhp-chip-f-val {
  font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.mhp-chip-f svg { width: 11px; height: 11px; flex: 0 0 auto; opacity: .55; }

.mhp-chip-f:hover svg { opacity: 1; }

.mhp-chip-clear {
  border: 0; background: none; font: inherit; font-size: 11px; font-weight: 600;
  color: var(--c-blue, #3b82f6); cursor: pointer; padding: 4px 6px; border-radius: 6px;
}

.mhp-chip-clear:hover { background: rgba(59, 130, 246, .1); }

/* ══════════════════════════════════════════════════════════════════════
   THE CHART — inline SVG, no library.
   Delivered as an area, opens and clicks as lines, ONE shared y-axis from
   zero. Giving opens their own scale is the commonest way an email chart
   lies, so the geometry refuses to.
   ══════════════════════════════════════════════════════════════════════ */
.mhp-chart {
  background: var(--wt-surface, #fff);
  border: 1px solid var(--line, #e2e8f0);
  border-radius: 12px; padding: 12px 14px 6px;
  margin-bottom: 14px;
}

.mhp-chart-head { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 6px; }

.mhp-chart-title { font-size: 12.5px; font-weight: 700; color: var(--ink1, #0f172a); }

.mhp-chart-legend { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }

.mhp-ch-key {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 11px; color: var(--ink3, #64748b);
}

.mhp-ch-key i { width: 9px; height: 9px; border-radius: 2px; flex: 0 0 auto; }

/* The source, stated. A chart that will not say where its numbers came
   from is a chart nobody can check. */
.mhp-chart-src { margin-left: auto; font-size: 10.5px; color: var(--ink4, #94a3b8); }

.mhp-chart-none { padding: 14px 2px 18px; font-size: 12px; color: var(--ink4, #94a3b8); }

/* preserveAspectRatio="none" stretches the plot to the card; a fixed
   height keeps the vertical scale stable as the column resizes. */
.mhp-chart-svg { display: block; width: 100%; height: 190px; overflow: visible; }

.mhp-ch-grid { stroke: var(--line, #e2e8f0); stroke-width: 1; }

.mhp-ch-ytick, .mhp-ch-xtick {
  fill: var(--ink4, #94a3b8); font-size: 10px;
  /* ⚠️ preserveAspectRatio="none" scales text horizontally with the
     viewBox, so the labels must not be stretched by it. */
  vector-effect: non-scaling-stroke;
}

/* One invisible hover target per day carrying a <title> — the tooltip is
   the browser's own, so the chart needs no JS listeners at all. */
.mhp-ch-hot { fill: transparent; }

.mhp-ch-hot:hover { fill: rgba(99, 102, 241, .07); }

/* A rail row that states rather than opens must not look clickable. */
.mhp-rail-static { cursor: default; }

@media (prefers-color-scheme: dark) {
.mhp-filterbar, .mhp-chart {
    background: rgba(148, 163, 184, .07);
    border-color: rgba(148, 163, 184, .2);
  }

.mhp-fb-sep { background: rgba(148, 163, 184, .25); }

.mhp-fb-chips { border-top-color: rgba(148, 163, 184, .22); }

.mhp-chip-f { background: rgba(15, 23, 42, .35); border-color: rgba(148, 163, 184, .25); }

.mhp-ch-grid { stroke: rgba(148, 163, 184, .2); }
}

/* ── "Not connected here" — a STATEMENT, not a warning ──────────────────
      Deliberately not .mh-src-down: no amber, no icon, no alarm. A feed this
      tenant has never had is a fact about the report's scope, and dressing it
      as an outage is what trains people to ignore the real banner sitting
      right underneath it. See absentSources() in marketing-hub-performance.js. */
.mhp-src-absent {
  font-size: 11.5px; color: var(--ink4, #94a3b8);
  padding: 2px 2px 10px; line-height: 1.45;
}

/* ══════════════════════════════════════════════════════════════════════════
   🚨 NOT ONE OF THESE MENUS COULD OPEN ON THE MERGED CRM TAB. EVER.
   ══════════════════════════════════════════════════════════════════════════
   Tyler, 2026-08-11: *"it's very important that all the dropdowns actually
   work."* They did not, and this is why.

   The one rule that reveals an open menu lives in work.css:

       .rp-drop.is-open .rp-drop-menu, body > .rp-drop-menu { display: block; }

   `tools/port-marketing-hub.cjs` drops any rule whose selector names a class
   the host stylesheet already owns — 151 rules from work.css alone — and this
   was one of them. So on crm.mrgcentral.net the vendored work.css defines
   `.rp-drop-menu { display: none }` and NOTHING anywhere turns it back on.

   Measured: clicking the period button added `.is-open` correctly, rotated the
   chevron correctly, and the menu stayed `display:none` with a 0×0 rect. Every
   dropdown on Performance rendered, responded and could not be used. No error,
   no warning — the single most expensive shape of bug in this codebase.

   ⚠️ SCOPED TO .mhp-drop, WHICH THIS FILE OWNS, so the porter cannot strip it
   on the way over. Naming `.rp-drop` here would be a rule about work.css's
   class and would be dropped exactly like the original. Upstream this is a
   harmless duplicate of a rule that already works.
   ══════════════════════════════════════════════════════════════════════════ */
.mhp-drop.is-open > .rp-drop-menu { display: block; }

/* The range summary is hidden unless it has something the controls do not
   already say (see renderPickers). `hidden` needs saying out loud because
   .rp-date-summary sets its own display —
   reference_hidden_attr_loses_to_author_display. */
.mhp-summary[hidden] { display: none !important; }

/* ══════════════════════════════════════════════════════════════════════════
   WHO BOUNCED, WHO OPTED OUT — AND WHAT THE CRM DID ABOUT THEM.
   ══════════════════════════════════════════════════════════════════════════
   Tyler, 2026-08-12: *"for unsubscribes, and kickbacks I want to see what
   emails did it, and I expect the CRM auto did something about it."*

   Three surfaces of one idea, and every class here is `mhp-`-prefixed so the
   porter cannot strip it on the way into the CRM (it drops any rule whose
   selector names a class crm.css / work.css already owns — see the note on
   .mhp-drop above, which is the bug that taught us).
   ══════════════════════════════════════════════════════════════════════════ */

/* ── 1 · the rail rows that open a list ── */
.mhp-rail-open { cursor: pointer; border-radius: 8px; transition: background .12s ease; }
.mhp-rail-open:hover { background: rgba(148, 163, 184, .12); }
.mhp-rail-open:focus-visible { outline: 2px solid var(--c-blue, #3b82f6); outline-offset: -2px; }
.mhp-rail-open.is-active { background: rgba(59, 130, 246, .1); }
.mhp-rail-open.is-active .mh-rail-title { font-weight: 700; }

/* 🚨 The exceptions row — SendGrid refuses them and the CRM has not noticed,
   so they are still inside every audience count on this platform. It is the
   only row on the rail that is a job rather than a number. */
.mhp-rail-alarm {
  background: rgba(220, 38, 38, .08);
  border: 1px solid rgba(220, 38, 38, .22);
  border-radius: 8px; margin-bottom: 6px; padding-left: 8px;
}
.mhp-rail-alarm .mh-rail-title { color: #b91c1c; font-weight: 700; }
.mhp-rail-alarm .mh-rail-when { color: #b91c1c; font-weight: 700; }

/* ── 2 · the bar above the addresses ── */
.mhp-people-lead {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 10px 12px; margin-bottom: 10px;
  background: rgba(148, 163, 184, .08);
  border: 1px solid rgba(148, 163, 184, .2); border-radius: 10px;
}
.mhp-people-back {
  display: inline-flex; align-items: center; gap: 4px; flex: 0 0 auto;
  font: inherit; font-size: 12px; font-weight: 600; cursor: pointer;
  padding: 5px 10px 5px 6px; border-radius: 7px;
  border: 1px solid rgba(148, 163, 184, .34); background: #fff; color: var(--ink2, #475569);
}
.mhp-people-back:hover { background: rgba(148, 163, 184, .14); }
.mhp-people-back svg { width: 14px; height: 14px; }
.mhp-people-lead-main { min-width: 0; }
.mhp-people-lead-title { font-size: 13px; font-weight: 700; color: var(--ink1, #0f172a); }
.mhp-people-lead-sub { font-size: 12px; color: var(--ink3, #64748b); margin-top: 3px; line-height: 1.5; }
.mhp-people-lead-sub b { color: var(--ink1, #0f172a); }
.mhp-people-lead-sub b.mhp-lead-bad { color: #b91c1c; }
.mhp-people-lead-warn { font-size: 11.5px; color: #b45309; margin-top: 4px; }
.mhp-people-lead-warn b { color: inherit; font-weight: 800; }

/* The scanner declaration. Not amber — amber is this file's colour for "we
   could not read something", and this is the opposite: a number we are certain
   about, reported deliberately. Slate, boxed, so it reads as a statement of
   method rather than as a fault. */
.mhp-lead-bot {
  color: var(--ink2, #475569); line-height: 1.55; margin-top: 6px;
  background: rgba(148, 163, 184, .12);
  border-left: 3px solid rgba(148, 163, 184, .7);
  border-radius: 0 7px 7px 0; padding: 7px 10px;
}
.mhp-lead-link {
  font: inherit; font-weight: 700; cursor: pointer; padding: 0;
  background: none; border: 0; border-bottom: 1px solid currentColor;
  color: var(--brand, #0891b2);
}

/* ⚠️ THE UNFOLD IS FULL WIDTH AND UNMISTAKABLE. It is the only thing standing
   between the reader and the other 5,891 rows, and a subtle link there reads as
   "the list ends here" — which is the one thing it must never say. */
.mhp-more {
  display: block; width: 100%; margin: 10px 0 2px;
  font: inherit; font-size: 12px; font-weight: 700; cursor: pointer;
  padding: 10px 12px; border-radius: 9px;
  border: 1px dashed rgba(148, 163, 184, .55);
  background: rgba(148, 163, 184, .08); color: var(--ink2, #475569);
}
.mhp-more:hover { background: rgba(148, 163, 184, .18); }

/* ── 3 · the address rows ── */
.mhp-row--person .ax-triage-title {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12.5px; letter-spacing: -.1px;
}
/* The receiving server's own words, which can be long and must not be styled
   as though we wrote them. */
.mhp-strip--reason {
  font-size: 11.5px; color: var(--ink3, #64748b); line-height: 1.45;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mhp-tag--crm { font-weight: 700; }

/* ══════════════════════════════════════════════════════════════════════════
   4 · EVERYTHING SENDGRID COUNTED — sixteen numbers, and not one scorecard.
   The tile row is capped at five by instruction; this is where the rest live,
   under SendGrid's own field names so a figure here can be checked against
   the same figure in their dashboard.
   ══════════════════════════════════════════════════════════════════════════ */
.mhp-allstats {
  margin: 12px 0 4px; padding: 12px 14px;
  background: rgba(148, 163, 184, .07);
  border: 1px solid rgba(148, 163, 184, .2); border-radius: 12px;
}
.mhp-allstats-head {
  font-size: 12px; font-weight: 700; color: var(--ink2, #475569);
  text-transform: uppercase; letter-spacing: .04em; margin-bottom: 10px;
}
.mhp-allstats-head span { font-weight: 500; text-transform: none; letter-spacing: 0; color: var(--ink4, #94a3b8); }
.mhp-allstats-grid {
  display: grid; gap: 8px;
  /* ⚠️ WIDE ENOUGH FOR THE LONGEST FIELD NAME. `unsubscribe_drops` ellipsised
     to `unsubscribe_d…` at 104px, which defeats the only purpose this grid has:
     checking our number against the same field in SendGrid own dashboard. */
  grid-template-columns: repeat(auto-fill, minmax(132px, 1fr));
}
.mhp-stat {
  background: var(--wt-page-bg, #fff); border: 1px solid rgba(148, 163, 184, .18);
  border-radius: 8px; padding: 7px 9px; min-width: 0;
}
.mhp-stat-val { font-size: 16px; font-weight: 700; color: var(--ink1, #0f172a); line-height: 1.2; }
.mhp-stat-key {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 10.5px; color: var(--ink4, #94a3b8); margin-top: 2px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mhp-allstats-foot { font-size: 11.5px; color: var(--ink3, #64748b); margin-top: 9px; line-height: 1.5; }
.mhp-allstats-ident { display: flex; flex-wrap: wrap; gap: 4px 14px; }
.mhp-allstats-ident .mhp-ok { color: #15803d; }
.mhp-allstats-ident .mhp-bad { color: #b45309; }

/* ══════════════════════════════════════════════════════════════════════════
   4b · WHERE IT LANDED — the placement panel, Deliverability only.

   Tyler, 2026-08-21: *"Just because it arrived doesn't mean it arrived in their
   actual inbox… It's important to not just show if it was delivered, but where
   it was delivered, if that's possible, and then obviously the ones that
   bounced."*

   ⚠️ THE LEAD PARAGRAPH IS NOT SMALL PRINT. It is the only thing preventing
   `Arrived: 5,255` from being read as five thousand inboxes, so it is set at
   body size in the body colour — 11.5px grey, like the other footnotes on this
   page, is exactly how a load-bearing sentence gets skipped.
   ══════════════════════════════════════════════════════════════════════════ */
.mhp-place {
  margin: 12px 0 4px; padding: 13px 15px;
  background: rgba(148, 163, 184, .07);
  border: 1px solid rgba(148, 163, 184, .2); border-radius: 12px;
}
.mhp-place-head {
  font-size: 12px; font-weight: 700; color: var(--ink2, #475569);
  text-transform: uppercase; letter-spacing: .04em; margin-bottom: 8px;
}
.mhp-place-lead {
  margin: 0 0 12px; font-size: 13px; line-height: 1.55; color: var(--ink2, #475569);
  max-width: 72ch;
}
.mhp-place-lead b { color: var(--ink1, #0f172a); }
.mhp-place-none {
  font-size: 12.5px; color: var(--ink3, #64748b); line-height: 1.5;
  padding: 2px 0 4px;
}

/* THE TWO JUNK NUMBERS — apart from the breakdown, because they are the only
   two that are about junk at all. Everything in the breakdown is a bad
   address. */
.mhp-place-junk {
  display: grid; gap: 9px; margin-bottom: 14px;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
}
.mhp-place-jcard {
  background: var(--wt-page-bg, #fff); border: 1px solid rgba(148, 163, 184, .22);
  border-radius: 10px; padding: 10px 12px;
  /* The status colour rides a left edge, not a fill: two filled cards beside a
     row of ten tiles reads as an eleventh and twelfth tile. */
  border-left: 3px solid var(--_pc, #94a3b8);
}
.mhp-place-jcard.is-ok   { --_pc: #16a34a; }
.mhp-place-jcard.is-warn { --_pc: #d97706; }
.mhp-place-jcard.is-bad  { --_pc: #dc2626; }
.mhp-place-jval {
  font-size: 24px; font-weight: 700; line-height: 1.1; color: var(--ink1, #0f172a);
  font-variant-numeric: tabular-nums;
}
.mhp-place-jlbl {
  font-size: 12px; font-weight: 600; color: var(--ink2, #475569); margin-top: 1px;
}
.mhp-place-jwhy {
  font-size: 11.5px; color: var(--ink3, #64748b); line-height: 1.45; margin-top: 5px;
}

.mhp-place-sub {
  font-size: 12px; font-weight: 700; color: var(--ink2, #475569);
  text-transform: uppercase; letter-spacing: .04em; margin: 0 0 9px;
}
.mhp-place-sub span {
  font-weight: 500; text-transform: none; letter-spacing: 0; color: var(--ink4, #94a3b8);
}

.mhp-place-rows { display: flex; flex-direction: column; gap: 11px; }
.mhp-place-row { min-width: 0; }
.mhp-place-rhead {
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
  font-size: 13px; margin-bottom: 4px;
}
.mhp-place-rlbl { font-weight: 650; color: var(--ink1, #0f172a); }
.mhp-place-code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 10.5px; color: var(--ink4, #94a3b8);
  background: rgba(148, 163, 184, .14); border-radius: 4px; padding: 1px 5px;
}
/* The count sits at the far end of the head line rather than after the label,
   so all of them line up down the panel and can be compared without reading. */
.mhp-place-rn {
  margin-left: auto; font-weight: 700; color: var(--ink2, #475569);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.mhp-place-track {
  height: 7px; border-radius: 4px; background: rgba(148, 163, 184, .18);
  overflow: hidden;
}
.mhp-place-track > i {
  display: block; height: 100%; border-radius: 4px;
  background: #64748b;   /* a bad ADDRESS is neutral — it is not our failing */
}
/* 🚨 ONLY THE TWO JUNK BUCKETS ARE COLOURED, and amber not red: 20 refusals of
   6,000 is a note, not an alarm, and painting the 476-strong "recipient
   refused" bar red would say the opposite of what its own sentence says. */
.mhp-place-row.is-junk .mhp-place-track > i { background: #d97706; }
.mhp-place-row.is-junk .mhp-place-rlbl { color: #b45309; }
.mhp-place-what {
  font-size: 12px; color: var(--ink3, #64748b); line-height: 1.5; margin-top: 5px;
  max-width: 76ch;
}
.mhp-place-dom {
  font-size: 11.5px; color: var(--ink4, #94a3b8); margin-top: 4px; line-height: 1.6;
}
.mhp-place-dom b { color: var(--ink2, #475569); font-weight: 650; }
/* The receiving server's own words. Monospace because it IS a quotation from a
   machine, and the evidence for the plain-English label above it. */
.mhp-place-rsn {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 10.5px; color: var(--ink4, #94a3b8);
  margin-top: 3px; line-height: 1.5;
  /* ⚠️ A 5.7.133 RESOLVER string runs to 180 characters. It must WRAP, not
     scroll and not ellipsise: the whole sentence is the point, and half of one
     is indistinguishable from a different refusal. */
  overflow-wrap: anywhere;
}
.mhp-place-rsn span { color: var(--ink3, #64748b); font-weight: 700; }

.mhp-place-foot {
  font-size: 11.5px; color: var(--ink3, #64748b); line-height: 1.55;
  margin-top: 13px; padding-top: 10px;
  border-top: 1px solid rgba(148, 163, 184, .2);
  display: flex; flex-direction: column; gap: 6px;
}
.mhp-place-foot b { color: var(--ink2, #475569); }

@media (prefers-color-scheme: dark) {
  .mhp-place-jcard { background: rgba(30, 41, 59, .6); border-color: rgba(148, 163, 184, .18); }
  .mhp-place-jval, .mhp-place-lead b, .mhp-place-rlbl { color: #e2e8f0; }
  .mhp-place-row.is-junk .mhp-place-rlbl { color: #fcd34d; }
  .mhp-place-jcard.is-ok { --_pc: #4ade80; }
  .mhp-place-jcard.is-warn { --_pc: #fbbf24; }
  .mhp-place-jcard.is-bad { --_pc: #f87171; }
  .mhp-place-row.is-junk .mhp-place-track > i { background: #fbbf24; }
  .mhp-place-dom b, .mhp-place-foot b { color: #cbd5e1; }
}

@media (prefers-color-scheme: dark) {
  .mhp-people-back { background: rgba(30, 41, 59, .7); color: #cbd5e1; border-color: rgba(148, 163, 184, .28); }
  .mhp-stat { background: rgba(30, 41, 59, .6); border-color: rgba(148, 163, 184, .18); }
  .mhp-stat-val { color: #e2e8f0; }
  .mhp-people-lead-title { color: #e2e8f0; }
  .mhp-people-lead-sub b { color: #e2e8f0; }
  .mhp-rail-alarm { background: rgba(220, 38, 38, .16); }
  .mhp-rail-alarm .mh-rail-title, .mhp-rail-alarm .mh-rail-when { color: #fca5a5; }
  .mhp-allstats-ident .mhp-ok { color: #86efac; }
  .mhp-allstats-ident .mhp-bad { color: #fcd34d; }
}

/* ══════════════════════════════════════════════════════════════════════════
   5 · TWO ROWS OF SCORECARDS — Deliverability only.

   Tyler, 2026-08-13: *"make sure that I'm seeing everything that I need to
   see, even if you have to put a whole second row of scorecards, just like how
   you have for some of them."*

   🚨 `.ax-cards-row` IS `display:flex` WITH `overflow-x:auto`, so simply
   returning ten tiles from tiles() does NOT make two rows — it makes one row
   with a horizontal scrollbar and five tiles hidden off the right edge, which
   is worse than the five it replaced because nothing says the others exist.
   Wrapping has to be asked for, and the basis has to be a fifth of the row or
   the second row sits under a ragged first one.
   ══════════════════════════════════════════════════════════════════════════ */
.ax-cards-row.mhp-cards--two {
  flex-wrap: wrap;
  overflow-x: visible;          /* nothing to scroll once it wraps */
  row-gap: 10px;
}
.ax-cards-row.mhp-cards--two > .ax-card {
  /* ⚠️ `calc(20% - 8px)` NOT `20%` — the 10px gap between five tiles is 40px
     of the row, and without subtracting its share the fifth tile wraps alone
     onto a line of its own. */
  flex: 0 0 calc(20% - 8px);
  max-width: calc(20% - 8px);
  padding: 15px 10px 13px;      /* ten tiles is a taller row; give it back */
}
.ax-cards-row.mhp-cards--two > .ax-card .ax-card-val { font-size: 22px; }
@media (max-width: 1100px) {
  .ax-cards-row.mhp-cards--two > .ax-card {
    flex-basis: calc(33.333% - 7px); max-width: calc(33.333% - 7px);
  }
}
@media (max-width: 640px) {
  .ax-cards-row.mhp-cards--two > .ax-card {
    flex-basis: calc(50% - 5px); max-width: calc(50% - 5px);
  }
}
/* The stagger only names six children; tiles seven to ten inherited
   `opacity:0` from the shared rule and never animated in — a permanently
   invisible second row. */
.ax-cards-row .ax-card:nth-child(7) { animation-delay: .35s; }
.ax-cards-row .ax-card:nth-child(8) { animation-delay: .4s; }
.ax-cards-row .ax-card:nth-child(9) { animation-delay: .45s; }
.ax-cards-row .ax-card:nth-child(10) { animation-delay: .5s; }

/* A tile whose number is a list of people, and a tile that opens one piece.
   Both are doors, and a door that looks exactly like a wall gets pressed once
   and never again. */
.ax-card--who::after,
.ax-card.mhp-card--goes::after {
  content: '';
  position: absolute; right: 9px; top: 11px; width: 13px; height: 13px;
  opacity: .34; transition: opacity .2s, transform .2s;
  background: currentColor;
  -webkit-mask: var(--_go-icon) center / contain no-repeat;
  mask: var(--_go-icon) center / contain no-repeat;
  color: var(--_ac, #64748b);
}
.ax-card--who {
  --_go-icon: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'><path d='M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2'/><circle cx='9' cy='7' r='4'/><path d='M23 21v-2a4 4 0 0 0-3-3.87'/><path d='M16 3.13a4 4 0 0 1 0 7.75'/></svg>");
}
.ax-card.mhp-card--goes {
  --_go-icon: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'><path d='M7 17 17 7'/><path d='M7 7h10v10'/></svg>");
}
.ax-card--who:hover::after,
.ax-card.mhp-card--goes:hover::after { opacity: .8; transform: translateY(-1px); }

/* ══════════════════════════════════════════════════════════════════════════
   6 · THE PEOPLE BEHIND A NUMBER — faces, names, and the link they pressed.

   Tyler, 2026-08-13: *"when it says Total clicks, it should be able to show us
   who clicked it. We can look at their account and show their profile
   picture."*
   ══════════════════════════════════════════════════════════════════════════ */
.mhp-who-face { flex: 0 0 auto; display: flex; align-items: center; justify-content: center; }
.mhp-face {
  position: relative; display: inline-flex; align-items: center; justify-content: center;
  width: 38px; height: 38px; border-radius: 50%; overflow: hidden; flex: 0 0 auto;
  /* Derived from the address, so one person is one colour on every repaint. */
  background: hsl(var(--f-h, 210) 62% 92%);
  border: 1px solid hsl(var(--f-h, 210) 45% 82%);
}
.mhp-face-init {
  font-size: 12.5px; font-weight: 700; letter-spacing: .2px;
  color: hsl(var(--f-h, 210) 55% 32%);
}
/* 🚨 THE PHOTOGRAPH SITS OVER THE INITIALS, IT DOES NOT REPLACE THEM. The img
   removes itself on error, and what is underneath has to already be correct —
   swapping the two on load is how a broken avatar leaves an empty circle. */
.mhp-face img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; border-radius: 50%;
}
.mhp-row--who { cursor: default; }
.mhp-row--who[data-crmperson] { cursor: pointer; }
.mhp-row--who[data-crmperson]:hover { background: rgba(99, 102, 241, .06); }
.mhp-lasturl {
  color: var(--ink2, #475569); text-decoration: none;
  border-bottom: 1px dotted rgba(148, 163, 184, .6);
}
.mhp-lasturl:hover { color: #6366f1; border-bottom-color: #6366f1; }
.mhp-people-lead--who { background: rgba(99, 102, 241, .07); border-color: rgba(99, 102, 241, .22); }

@media (prefers-color-scheme: dark) {
  .mhp-face { background: hsl(var(--f-h, 210) 32% 24%); border-color: hsl(var(--f-h, 210) 30% 34%); }
  .mhp-face-init { color: hsl(var(--f-h, 210) 60% 82%); }
  .mhp-row--who[data-crmperson]:hover { background: rgba(99, 102, 241, .14); }
  .mhp-lasturl { color: #cbd5e1; }
  .mhp-people-lead--who { background: rgba(99, 102, 241, .14); border-color: rgba(99, 102, 241, .3); }
}


/* ══════════════════════════════════════════════════════════════════════════
   THE TIME CHART — the one chart on this page. See chartHtml() for why it is
   two panels rather than one, and why the scanner series is hatched grey.

   ⚠️ THE PANELS SIT SIDE BY SIDE ON A WIDE SCREEN AND STACK BELOW 900px. Two
   1000-unit viewBoxes squeezed into half a card each is where axis labels
   collide, so the grid gives them a real minimum and lets them stack instead.
   ══════════════════════════════════════════════════════════════════════════ */
.mhp-tc-panels { display: grid; grid-template-columns: 1fr; gap: 18px; padding: 4px 0 2px; }
.mhp-tc-panels--two { grid-template-columns: repeat(auto-fit, minmax(330px, 1fr)); }

.mhp-tc-panel { min-width: 0; }

.mhp-tc-ptitle { font-size: 11.5px; font-weight: 700; color: var(--ink1, #0f172a); }
.mhp-tc-psub {
  font-size: 10.5px; color: var(--ink4, #94a3b8); margin-top: 1px; margin-bottom: 4px;
}

/* ⚠️ NOT preserveAspectRatio-stretched height: the container has to include the
   x-axis band or the card grows a tiny nested scrollbar (a documented
   anti-pattern). 168 viewBox units at this height keeps the ticks inside. */
.mhp-tc-svg { display: block; width: 100%; height: 168px; overflow: visible; }

/* Thin marks. The fill carries identity; nothing gets a stroke — a border drawn
   round a bar to separate it from its neighbour is what the 2px gap is for. */
.mhp-tc-bar { shape-rendering: crispEdges; }

.mhp-tc-ytick { font-size: 9px; font-variant-numeric: tabular-nums; }

/* Selective direct labels: the peak of each series, and nothing else. Text wears
   its series colour ONLY here, where it is annotating one mark it sits on top
   of — every other number on this page stays in ink tokens. */
.mhp-tc-peak {
  font-size: 9.5px; font-weight: 800; font-variant-numeric: tabular-nums;
  paint-order: stroke; stroke: var(--surf, #fff); stroke-width: 3px; stroke-linejoin: round;
}

.mhp-tc-pnote {
  font-size: 10.5px; color: var(--ink3, #64748b); line-height: 1.5; margin-top: 6px;
  padding-left: 9px; border-left: 2px solid var(--border, #e8ecf0);
}

.mhp-tc-foot {
  font-size: 10.5px; color: var(--ink4, #94a3b8); line-height: 1.5;
  padding: 10px 2px 0; margin-top: 6px; border-top: 1px solid var(--border, #eef2f7);
}

/* The scanner key, hatched to match its bars — grey-vs-colour is exactly what a
   monochrome print or forced-colors throws away, so the texture is the real
   encoding and the colour is the convenience. */
.mhp-ch-key--ghost i {
  background-image: repeating-linear-gradient(135deg,
    rgba(148, 163, 184, .85) 0, rgba(148, 163, 184, .85) 2px,
    rgba(148, 163, 184, .22) 2px, rgba(148, 163, 184, .22) 5px);
}

/* ══════════════════════════════════════════════════════════════════════════
   THE CAMPAIGN PICKER — "this needs to be a big dropdown. It needs to look
   beautiful." Cards with the email itself on them; see renderPickers().

   ⚠️ WIDTH COMES OFF THE MENU, NOT THE BUTTON. `.rp-drop-menu` is
   `left:0; right:0`, so it inherits the 158px control and no amount of padding
   inside can widen it — that is why the old list wrapped a campaign name onto
   six lines. `right:auto` + a min-width is the whole fix, and it has to be
   scoped to this menu so the period and channel pickers stay compact.
   ══════════════════════════════════════════════════════════════════════════ */
#mhPerfCampDrop > .rp-drop-menu {
  right: auto; min-width: 420px; max-width: min(520px, calc(100vw - 48px));
  border-radius: 14px;
  box-shadow: 0 18px 44px rgba(15, 23, 42, .16), 0 3px 10px rgba(15, 23, 42, .06);
}
#mhPerfCampDrop .rp-drop-search { padding: 12px 14px; font-size: 12.5px; }
#mhPerfCampDrop .rp-drop-list { max-height: 396px; padding: 6px; }

.mhp-camp-item {
  display: flex; align-items: center; gap: 12px;
  padding: 8px; border-radius: 10px;
  /* the row is the hit target — 60px of picture plus two lines of text */
  min-height: 60px;
}
.mhp-camp-item + .mhp-camp-item { margin-top: 2px; }

.mhp-camp-item:hover { background: rgba(99, 102, 241, .07); }
.mhp-camp-item.is-active { background: rgba(99, 102, 241, .11); }

/* A 3px spine in the piece's own channel colour: identity without another chip. */
.mhp-camp-item.is-active .mhp-camp-thumb { box-shadow: 0 0 0 2px var(--_cc, #6366f1); }

.mhp-camp-thumb {
  position: relative; flex: 0 0 auto;
  width: 68px; height: 50px; border-radius: 8px; overflow: hidden;
  border: 1px solid var(--border, #e5e7eb); background: #fff;
  display: flex; align-items: center; justify-content: center;
}
.mhp-camp-thumb img { width: 100%; height: 100%; object-fit: cover; object-position: top center; }

/* Same scaled-document idiom as the list row, sized for this box. The iframe is
   inert: sandbox="" plus pointer-events:none, so the CARD keeps the click. */
.mhp-camp-thumb .mh-rowshot { position: absolute; inset: 0; pointer-events: none; }
.mhp-camp-thumb .mh-rowshot iframe {
  position: absolute; top: 0; left: 0;
  width: 400%; height: 400%;
  transform: scale(.25); transform-origin: 0 0;
  border: 0; background: #fff; pointer-events: none;
}

/* No artwork stored: a letter in the channel's colour. Still a mark to aim at
   rather than a fourth line of prose. */
.mhp-camp-thumb--mark {
  font-size: 20px; font-weight: 800; letter-spacing: -.5px;
  color: var(--_cc, #6366f1);
  background: color-mix(in srgb, var(--_cc, #6366f1) 12%, #fff);
  border-color: color-mix(in srgb, var(--_cc, #6366f1) 26%, var(--border, #e5e7eb));
}
.mhp-camp-thumb--all { background: rgba(148, 163, 184, .1); border-style: dashed; }
.mhp-camp-thumb--all svg { width: 22px; height: 22px; stroke: var(--ink4, #94a3b8); }

.mhp-camp-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }

/* ⚠️ TWO LINES MAX, then an ellipsis. An unclamped name is what produced the
   six-line option; `title=` carries the whole string for anyone who needs it. */
.mhp-camp-name {
  font-size: 12.5px; font-weight: 650; line-height: 1.35; color: var(--ink1, #0f172a);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; white-space: normal;
}
.mhp-camp-meta {
  font-size: 10.5px; color: var(--ink4, #94a3b8); line-height: 1.3;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

.mhp-camp-none { opacity: .65; pointer-events: none; padding: 14px 10px; font-size: 12px; }

/* The closed button shows the short name and must not stretch the filter bar. */
#mhPerfCampDrop .rp-drop-val {
  max-width: 190px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

@media (max-width: 720px) {
  #mhPerfCampDrop > .rp-drop-menu { min-width: min(420px, calc(100vw - 32px)); }
}

@media (prefers-color-scheme: dark) {
  .mhp-tc-ptitle { color: #e2e8f0; }
  .mhp-tc-pnote { color: #94a3b8; border-left-color: rgba(148, 163, 184, .22); }
  .mhp-tc-foot { color: #94a3b8; border-top-color: rgba(148, 163, 184, .2); }
  .mhp-tc-peak { stroke: #111827; }

  #mhPerfCampDrop > .rp-drop-menu {
    box-shadow: 0 18px 44px rgba(0, 0, 0, .5), 0 3px 10px rgba(0, 0, 0, .3);
  }
  .mhp-camp-item:hover { background: rgba(99, 102, 241, .16); }
  .mhp-camp-item.is-active { background: rgba(99, 102, 241, .22); }
  .mhp-camp-name { color: #e2e8f0; }
  .mhp-camp-thumb { background: #0f172a; border-color: rgba(148, 163, 184, .28); }
  .mhp-camp-thumb--all { background: rgba(148, 163, 184, .14); }
  .mhp-camp-thumb--mark { background: color-mix(in srgb, var(--_cc, #6366f1) 22%, #0f172a); }
}

/* ══════════════════════════════════════════════════════════════════════════
   THE PIECE AND CHANNEL MENUS WEAR THE CAMPAIGN MENU'S CLOTHES

   Tyler, 2026-08-21: *"just like how you did with the campaigns, make it a
   beautiful picture, and the name is better. You need to do the same thing with
   the pieces dropdown… all the designs are actually thought out and polished."*

   One filter bar had two visual languages in it: cards with the rendered email
   on the campaign menu, and a 158px column of clipped strings on the two menus
   beside it. Everything below reuses the campaign card's own primitives —
   `.mhp-camp-item` / `-thumb` / `-main` / `-name` / `-meta` — so the two
   pickers cannot drift again: there is only one card.

   ⚠️ WIDTH COMES OFF THE MENU, NOT THE BUTTON, and it has to be scoped per
   menu. `.rp-drop-menu` is `left:0; right:0`, so it inherits the control's
   width and no padding inside can widen it. `right:auto` + a min-width is the
   whole fix — and the period menu must NOT get it, or a seven-item list of
   dates becomes 440px wide for no reason.
   ══════════════════════════════════════════════════════════════════════════ */
#mhPerfPieceDrop > .rp-drop-menu {
  right: auto; min-width: 440px; max-width: min(540px, calc(100vw - 48px));
  border-radius: 14px;
  box-shadow: 0 18px 44px rgba(15, 23, 42, .16), 0 3px 10px rgba(15, 23, 42, .06);
}
#mhPerfPieceDrop .rp-drop-search { padding: 12px 14px; font-size: 12.5px; }
#mhPerfPieceDrop .rp-drop-list { max-height: 420px; padding: 6px; }

/* The closed button shows the shortened name and must not stretch the bar. */
#mhPerfPieceDrop .rp-drop-val {
  max-width: 210px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

#mhPerfChanDrop > .rp-drop-menu {
  right: auto; min-width: 252px; border-radius: 12px;
  box-shadow: 0 14px 34px rgba(15, 23, 42, .14), 0 2px 8px rgba(15, 23, 42, .05);
}
#mhPerfChanDrop .rp-drop-list { padding: 6px; }

/* ── THE THIRD LINE ─────────────────────────────────────────────────────
      What a piece belongs to, or the subject line its recipients actually
      saw. The little uppercase word in front of it is the label, so the
      VALUE is what the eye lands on. */
.mhp-camp-sub {
  font-size: 10.5px; color: var(--ink3, #64748b); line-height: 1.35;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.mhp-camp-in {
  font-size: 9px; font-weight: 750; letter-spacing: .07em; text-transform: uppercase;
  color: var(--ink4, #94a3b8); margin-right: 5px;
}

/* "Everything" is an option like the others, but it is not one OF them — one
   hairline says so without a heading. */
.mhp-camp-item--all { border-bottom: 1px solid var(--border, #eef2f7); margin-bottom: 5px; }

/* ── WHAT NARROWED THIS MENU, AND THE WAY BACK OUT ──────────────────────
      The cascade Tyler asked to be able to see: a sentence at the top of the
      menu whose list another filter has shortened, and one button that widens
      it again. Cyan, not amber — this is information, not a warning. */
.mhp-pick-head {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  margin: 2px 2px 6px; padding: 8px 10px;
  border-radius: 9px;
  background: rgba(8, 145, 178, .07);
  border: 1px solid rgba(8, 145, 178, .2);
  font-size: 11px; line-height: 1.35; color: var(--ink2, #334155);
}
.mhp-pick-head-txt { min-width: 0; }
.mhp-pick-head-txt b { font-weight: 700; color: var(--ink1, #0f172a); }
.mhp-pick-wide {
  flex: 0 0 auto; white-space: nowrap; cursor: pointer;
  border: 1px solid rgba(8, 145, 178, .38); background: #fff; color: #0e7490;
  font-size: 10.5px; font-weight: 700; border-radius: 999px; padding: 4px 10px;
}
.mhp-pick-wide:hover { background: rgba(8, 145, 178, .12); }

/* ── A CHANNEL IS A KIND, NOT AN ARTEFACT ───────────────────────────────
      So it gets the mark and the counts, and deliberately NOT a thumbnail:
      one send's artwork on the "Email" row would claim the channel is that
      send. Same two-line body as every other option. */
.mhp-chan-item {
  display: flex; align-items: center; gap: 10px;
  padding: 8px; border-radius: 10px; min-height: 46px;
}
.mhp-chan-item + .mhp-chan-item { margin-top: 2px; }
.mhp-chan-item:hover { background: rgba(99, 102, 241, .07); }
.mhp-chan-item.is-active { background: rgba(99, 102, 241, .11); }
.mhp-chan-ico {
  flex: 0 0 auto; width: 32px; height: 32px; border-radius: 9px;
  display: flex; align-items: center; justify-content: center;
  color: var(--_cc, #6366f1);
  background: color-mix(in srgb, var(--_cc, #6366f1) 12%, #fff);
  border: 1px solid color-mix(in srgb, var(--_cc, #6366f1) 26%, var(--border, #e5e7eb));
}
/* KIND_ICONS ship without presentation attributes — they inherit them from
   whatever draws them, which here is this box. */
.mhp-chan-ico svg {
  width: 17px; height: 17px; fill: none; stroke: currentColor;
  stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round;
}
.mhp-chan-ico--all {
  color: var(--ink4, #94a3b8); background: rgba(148, 163, 184, .1); border-style: dashed;
}

/* ══════════════════════════════════════════════════════════════════════════
   THE TRIGGERS THEMSELVES — "when I go to campaigns and it says 'All
   Campaigns'… they all really work."

   A row of buttons all reading "All …" is indistinguishable from a row of
   labels. These three states are the whole difference:
     · a count pill, so the size of the menu is known before it is opened and
       a filter that shrinks it is visible from OUTSIDE the menu;
     · `is-set` — an accent, so a control with a selection cannot be mistaken
       for an idle one;
     · `is-lonely` — dimmed, because one option is not a choice.
   ⚠️ Scoped to `.mhp-drop`, which this file owns. Restyling a bare
   `.rp-drop-btn` here would drift Work's report builder, which ships the
   control.
   ══════════════════════════════════════════════════════════════════════════ */
.mhp-fb-n {
  display: inline-block; margin-left: 6px; padding: 1px 6px;
  font-style: normal; font-size: 10px; font-weight: 700; line-height: 1.5;
  border-radius: 999px; background: rgba(148, 163, 184, .18);
  color: var(--ink3, #64748b); vertical-align: 1px;
}

.mhp-drop.is-set > .rp-drop-btn {
  border-color: rgba(79, 70, 229, .45);
  background: rgba(99, 102, 241, .08);
  color: var(--ink1, #0f172a); font-weight: 650;
}
.mhp-drop.is-set > .rp-drop-btn svg { stroke: #4f46e5; }
.mhp-drop.is-lonely > .rp-drop-btn { opacity: .7; }

/* ── THE CAPTION IS NOT A DATE SUMMARY ANY MORE ──────────────────────────
      It is on screen whether or not anything is filtered, because it is the
      only line that tells you the pickers did something. Two consequences:
        · `.rp-date-summary::before` staples a 📅 onto it, which says "period"
          about a sentence that is mostly about scope. Gone.
        · at the end of a wrapping flex row it landed on row one or row two
          depending on the viewport. A caption cannot move around: it takes its
          own line, under the controls it is describing, always.
      ⚠️ `is-invalid` still owns it for an unfinished custom range — that one is
      an unanswered question, not a caption. */
.mhp-summary {
  flex: 1 0 100%; margin: 9px 0 0; padding: 0;
  background: none; border: 0; border-radius: 0;
  color: var(--ink4, #94a3b8); font-size: 11px; font-weight: 600;
  max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.mhp-summary::before { content: none; }
.mhp-summary.is-invalid { color: #dc2626; }

@media (max-width: 860px) {
  #mhPerfPieceDrop > .rp-drop-menu { min-width: min(440px, calc(100vw - 32px)); }
  .mhp-summary { max-width: 100%; }
}

/* ══════════════════════════════════════════════════════════════════════════
   SINGLE CHOICE, SO NO CHECKBOXES.

   Both card menus are `.rp-drop--multi` — Work's MULTI-select control — which
   draws a 14px checkbox in front of every item and indents it 32px. Measured on
   screen: every campaign and every piece had an unchecked box beside it and
   "All pieces" had a ticked one, which promises a control that adds and removes
   from a set. These pick ONE: choosing a campaign replaces the campaign. The
   box was a false promise and the indent was 32px of card width spent on it.
   The multi-select markup stays (`.rp-drop-menu--search` rides on it), and the
   chosen row is marked the way a single-select .rp-drop marks one: the tick at
   the end of the row, plus the tint and the coloured spine it already had.
   ══════════════════════════════════════════════════════════════════════════ */
#mhPerfCampDrop .rp-drop-list .rp-drop-item,
#mhPerfPieceDrop .rp-drop-list .rp-drop-item { padding-left: 8px; }

#mhPerfCampDrop .rp-drop-list .rp-drop-item::before,
#mhPerfPieceDrop .rp-drop-list .rp-drop-item::before { display: none; }

#mhPerfCampDrop .rp-drop-list .rp-drop-item.is-active::after,
#mhPerfPieceDrop .rp-drop-list .rp-drop-item.is-active::after {
  content: '✓'; position: static; transform: none; margin-left: auto;
  flex: 0 0 auto; padding-left: 8px;
  font-size: 13px; font-weight: 800; color: #4f46e5;
}


/* ══════════════════════════════════════════════════════════════════════════
   THE BOUNCED TAB — WHY IT BOUNCED, AND WHAT TO DO ABOUT IT
   ══════════════════════════════════════════════════════════════════════════
   Tyler, 2026-08-21: *"in the Bounced tab, I'd like to see scorecards for all
   the different reasons why it bounced… and then have a resend button."*

   ⚠️ LIGHT-ONLY, WITH NO `prefers-color-scheme` BLOCK, DELIBERATELY. See the
   note at the top of the dark section below: this app has no dark theme, and the
   dark blocks this stylesheet inherited from the upstream hub are already a
   live bug (light-grey ink on white cards). Adding a sixth one would be adding
   to it.

   ⚠️ AND IT LIVES INSIDE THE LIST'S LEAD BAND, not in #mhPerfCards. The cards up
   there count events across the period; these count the rows immediately below.
   Same strip would invite the two to be added together.
   ══════════════════════════════════════════════════════════════════════════ */
.mhp-bw { margin-top: 10px; padding-top: 10px; border-top: 1px solid rgba(99, 102, 241, .18); }

.mhp-bw-note {
  font-size: 11.5px; line-height: 1.55; color: var(--ink3, #64748b); margin-bottom: 8px;
}
.mhp-bw-note b { color: var(--ink1, #0f172a); font-weight: 800; }
.mhp-bw-note--bad { color: #b45309; }
.mhp-bw-note--bad b { color: #b45309; }
.mhp-bw-link {
  background: none; border: 0; padding: 0; font: inherit; color: #4f46e5;
  font-weight: 700; cursor: pointer; text-decoration: underline;
}

/* ── The scorecards ──────────────────────────────────────────────────────
   ⚠️ A SCROLLING ROW, NOT A WRAPPING GRID. Nine buckets at a readable width is
   wider than the panel on a laptop; wrapping them to three rows pushes the list
   itself below the fold, and the list is the thing being worked. */
.mhp-bw-cards {
  display: flex; gap: 8px; overflow-x: auto; padding-bottom: 6px; margin-bottom: 8px;
  scrollbar-width: thin;
}
.mhp-bwc {
  flex: 0 0 auto; min-width: 132px; max-width: 190px; text-align: left;
  padding: 8px 10px 9px; border-radius: 10px; cursor: pointer;
  background: color-mix(in srgb, var(--_ac, #64748b) 7%, #fff);
  border: 1px solid color-mix(in srgb, var(--_ac, #64748b) 22%, #fff);
  transition: background .12s, border-color .12s, transform .06s;
}
.mhp-bwc:hover { background: color-mix(in srgb, var(--_ac, #64748b) 13%, #fff); }
.mhp-bwc:active { transform: translateY(1px); }
/* The chosen card has to be unmistakable — it is a FILTER over the list below,
   and a filter you cannot see is a list that looks wrong. */
.mhp-bwc.is-on {
  background: color-mix(in srgb, var(--_ac, #64748b) 16%, #fff);
  border-color: var(--_ac, #64748b);
  box-shadow: inset 0 0 0 1px var(--_ac, #64748b);
}
.mhp-bwc-n {
  font-size: 20px; font-weight: 800; line-height: 1.1; color: var(--_ac, #0f172a);
  font-variant-numeric: tabular-nums;
}
.mhp-bwc-l {
  font-size: 11.5px; font-weight: 700; color: var(--ink1, #0f172a); margin-top: 2px;
  line-height: 1.3;
}
.mhp-bwc-s {
  font-size: 10.5px; color: var(--ink4, #94a3b8); margin-top: 2px; line-height: 1.35;
}
/* One phrase saying what the bucket MEANS for the person, so the right button is
   legible without opening a tooltip. */
.mhp-bwc-v {
  font-size: 10px; font-weight: 800; text-transform: uppercase; letter-spacing: .04em;
  margin-top: 5px; color: var(--ink4, #94a3b8);
}
.mhp-bwc-v--dead { color: #b91c1c; }
.mhp-bwc-v--retry { color: #0d9488; }
.mhp-bwc-v--junk { color: #b45309; }

.mhp-bw-what {
  font-size: 11.5px; line-height: 1.55; color: var(--ink2, #475569);
  background: rgba(148, 163, 184, .1); border-radius: 8px; padding: 7px 9px; margin-bottom: 8px;
}
.mhp-bw-what b { color: var(--ink1, #0f172a); }
.mhp-bw-codes {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 10.5px;
  color: var(--ink4, #94a3b8);
}

/* ── The selection bar ───────────────────────────────────────────────────── */
.mhp-bw-bar {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 8px 9px; border-radius: 9px;
  background: #fff; border: 1px solid var(--border, #e2e8f0);
}
.mhp-bw-all {
  display: inline-flex; align-items: center; gap: 6px; cursor: pointer;
  font-size: 11.5px; font-weight: 700; color: var(--ink2, #475569);
}
.mhp-bw-all input { cursor: pointer; }
.mhp-bw-count { font-size: 11.5px; color: var(--ink3, #64748b); margin-right: auto; }
.mhp-bw-count b { color: var(--ink1, #0f172a); font-weight: 800; }
.mhp-bw-busy {
  font-size: 11.5px; font-weight: 700; color: #4f46e5;
  display: inline-flex; align-items: center; gap: 6px;
}
/* ⚠️ A SPINNER, BECAUSE A REINSTATEMENT OF 400 PEOPLE IS SIXTEEN ROUND TRIPS.
   Static text through a half-minute of work reads as a frozen screen, which is
   how somebody presses the button twice. */
.mhp-bw-busy::before {
  content: ''; width: 11px; height: 11px; border-radius: 50%;
  border: 2px solid rgba(79, 70, 229, .28); border-top-color: #4f46e5;
  animation: mhp-bw-spin .7s linear infinite;
}
@keyframes mhp-bw-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .mhp-bw-busy::before { animation-duration: 2.4s; }
}

.mhp-bw-btn {
  font-size: 11.5px; font-weight: 700; padding: 6px 11px; border-radius: 8px;
  cursor: pointer; white-space: nowrap;
  background: #fff; color: var(--ink2, #475569); border: 1px solid var(--border, #cbd5e1);
  transition: background .12s, border-color .12s, color .12s;
}
.mhp-bw-btn:hover:not(:disabled) { background: rgba(99, 102, 241, .07); border-color: #a5b4fc; color: #4f46e5; }
/* ⚠️ DISABLED HAS TO LOOK DISABLED. Four buttons that respond to nothing because
   nobody is ticked is the "dead button" complaint in its purest form. */
.mhp-bw-btn:disabled { opacity: .45; cursor: not-allowed; }
.mhp-bw-btn--go {
  background: #4f46e5; border-color: #4f46e5; color: #fff;
}
.mhp-bw-btn--go:hover:not(:disabled) { background: #4338ca; border-color: #4338ca; color: #fff; }
.mhp-bw-btn--bad { color: #b91c1c; border-color: rgba(185, 28, 28, .34); }
.mhp-bw-btn--bad:hover:not(:disabled) { background: rgba(185, 28, 28, .07); border-color: #b91c1c; color: #b91c1c; }

/* ── What the last action did. ABOVE the list, never below it — a result 810px
   under the button that caused it reads as a dead button. ─────────────────── */
.mhp-bw-res {
  margin-top: 8px; padding: 8px 10px; border-radius: 9px; font-size: 11.5px; line-height: 1.6;
  background: rgba(13, 148, 136, .09); border: 1px solid rgba(13, 148, 136, .28);
  color: var(--ink2, #475569);
}
.mhp-bw-res b { color: var(--ink1, #0f172a); font-weight: 800; }
.mhp-bw-res--bad { background: rgba(185, 28, 28, .07); border-color: rgba(185, 28, 28, .28); }
.mhp-bw-res--bad b { color: #b91c1c; }

/* ── The tick box on a row ───────────────────────────────────────────────── */
.mhp-row--pick { padding-left: 4px; }
.mhp-pick {
  display: inline-flex; align-items: center; justify-content: center;
  /* A 26px target on a 4px checkbox: the row underneath opens a CRM record, so a
     near miss is a navigation, not a nothing. */
  width: 26px; min-width: 26px; height: 26px; cursor: pointer; flex: 0 0 auto;
}
.mhp-pick input { cursor: pointer; width: 14px; height: 14px; }
.mhp-row--who.is-picked { background: rgba(79, 70, 229, .08); }
.mhp-row--who.is-picked:hover { background: rgba(79, 70, 229, .12); }

/* ── The reason chip ─────────────────────────────────────────────────────
   ⚠️ "NOT ON A SUPPRESSION LIST" IS A DIFFERENT COLOUR ON PURPOSE. It is the one
   chip here whose conclusion is "nothing is in the way of the next send", and
   drawing it like the refusals would invert what the row says. */
.mhp-tag--why {
  background: rgba(245, 158, 11, .13); color: #92400e;
  border: 1px solid rgba(245, 158, 11, .3); font-weight: 700;
}
.mhp-tag--why-dead { background: rgba(220, 38, 38, .11); color: #991b1b; border-color: rgba(220, 38, 38, .3); }
.mhp-tag--why-none { background: rgba(8, 145, 178, .1); color: #0e7490; border-color: rgba(8, 145, 178, .28); }

/* ── What the CRM already did about them ─────────────────────────────────
   🚨 `none` IS THE LOUD ONE. SendGrid will refuse this address for ever and this
   CRM still counts them as mailable — they are in every audience total and every
   send screen's recipient count. That is the gap the tab exists to show, so it
   is drawn as a warning rather than as an absence. */
.mhp-tag--verdict { font-weight: 700; border: 1px solid transparent; }
.mhp-verdict--none {
  background: rgba(185, 28, 28, .12); color: #991b1b; border-color: rgba(185, 28, 28, .35);
}
.mhp-verdict--unlinked { background: rgba(124, 58, 237, .1); color: #6d28d9; border-color: rgba(124, 58, 237, .26); }
.mhp-verdict--unlink-pending { background: rgba(245, 158, 11, .12); color: #92400e; border-color: rgba(245, 158, 11, .3); }
.mhp-verdict--pending { background: rgba(245, 158, 11, .1); color: #92400e; border-color: rgba(245, 158, 11, .26); }
.mhp-verdict--suppressed { background: rgba(100, 116, 139, .12); color: #475569; border-color: rgba(100, 116, 139, .26); }
.mhp-verdict--absent { background: rgba(148, 163, 184, .14); color: #64748b; border-color: rgba(148, 163, 184, .3); }

/* Narrow panels: the bar stacks rather than squeezing four labels to nothing. */
@media (max-width: 760px) {
  .mhp-bw-bar { gap: 6px; }
  .mhp-bw-count { margin-right: 0; width: 100%; }
  .mhp-bw-btn { flex: 1 1 auto; text-align: center; }
}

/* ══════════════════════════════════════════════════════════════════════════
   🚨 THIS APP HAS NO DARK THEME — AND THIS STYLESHEET HAS ONE.

   Measured 2026-08-21 under `prefers-color-scheme: dark`: the CRM stays white
   (crm.css contains not one prefers-color-scheme rule; the app is light-only)
   while this file — a copy of the upstream marketing hub's stylesheet, where a
   dark theme is real — flips the menu's INK to #e2e8f0. Light grey names on a
   white card. That has been live for as long as the campaign card picker has,
   on any machine whose OS is set to dark.

   So the picker's dark block is turned back OFF here, explicitly and in one
   place, rather than left as a trap for the next person who opens the menu on
   a dark laptop. Same declarations, light values, last in the file.
   ⚠️ The other five dark blocks in this stylesheet (tags, rows, the chart)
   have exactly the same problem and are deliberately NOT touched here: that is
   a fleet decision about whether the CRM gets a theme, not something a picker
   change should quietly settle.
   ══════════════════════════════════════════════════════════════════════════ */
@media (prefers-color-scheme: dark) {
  #mhPerfCampDrop > .rp-drop-menu,
  #mhPerfPieceDrop > .rp-drop-menu,
  #mhPerfChanDrop > .rp-drop-menu {
    box-shadow: 0 18px 44px rgba(15, 23, 42, .16), 0 3px 10px rgba(15, 23, 42, .06);
  }
  .mhp-camp-name { color: var(--ink1, #0f172a); }
  .mhp-camp-meta { color: var(--ink4, #94a3b8); }
  .mhp-camp-sub { color: var(--ink3, #64748b); }
  .mhp-camp-item:hover, .mhp-chan-item:hover { background: rgba(99, 102, 241, .07); }
  .mhp-camp-item.is-active, .mhp-chan-item.is-active { background: rgba(99, 102, 241, .11); }
  .mhp-camp-item--all { border-bottom-color: var(--border, #eef2f7); }
  .mhp-camp-thumb { background: #fff; border-color: var(--border, #e5e7eb); }
  .mhp-camp-thumb--all { background: rgba(148, 163, 184, .1); }
  .mhp-camp-thumb--mark,
  .mhp-chan-ico { background: color-mix(in srgb, var(--_cc, #6366f1) 12%, #fff); }
  .mhp-chan-ico--all { background: rgba(148, 163, 184, .1); }
  .mhp-pick-head {
    background: rgba(8, 145, 178, .07); border-color: rgba(8, 145, 178, .2);
    color: var(--ink2, #334155);
  }
  .mhp-pick-head-txt b { color: var(--ink1, #0f172a); }
  .mhp-pick-wide { background: #fff; color: #0e7490; border-color: rgba(8, 145, 178, .38); }
  .mhp-fb-n { background: rgba(148, 163, 184, .18); color: var(--ink3, #64748b); }
}

/* ══════════════════════════════════════════════════════════════════════════
   THE MOVABLE HALF OF THE BAR — `.mhp-scope`

   Tyler, 2026-08-21: *"there's nowhere for me to set or change that filter …
   make sure that that shows for all of them when I go to Pieces and Approvals.
   Next to Overview, it also shows that filter … because then it just looks
   like it's a hidden filter."*

   One node holding the four narrowing pickers, the chips and the note.
   crm-marketing.js moves it into whichever section's top bar is open and back
   here when Performance is. Two layout modes and nothing in between:

     at home    `display:contents` — the children stay flex items of
                .mhp-fb-row, so the Performance bar is laid out EXACTLY as it
                was before this wrapper existed. That is the whole reason the
                wrapper is `contents` and not a flex box of its own.
     docked     `.is-docked` — its own wrapping flex row inside a
                `.crm-mkt-bar`, which is already sticky there.

   ⚠️ `display:contents` REMOVES THE BOX, NOT THE CHILDREN. Nothing may be
   styled on `.mhp-scope` itself in the home mode — no padding, no border, no
   background: none of it would render. Style the children.
   ══════════════════════════════════════════════════════════════════════════ */
.mhp-scope { display: contents; }

/* Both modes: the chip row and the note take their own line under the
   controls they are describing. As a flex ITEM (which the chips became the
   moment they moved inside this wrapper) a block-level element no longer gets
   the full width by itself. */
.mhp-scope > .mhp-fb-chips,
.mhp-scope > .mhp-scope-note { flex: 1 0 100%; min-width: 0; }

.mhp-scope-note {
  margin: 7px 0 0; font-size: 11px; font-weight: 600;
  color: var(--ink4, #94a3b8);
}
.mhp-scope-note[hidden] { display: none; }

.mhp-scope.is-docked {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  flex: 1 1 auto; min-width: 0;
}

/* 🚨 THE CAPTION DOES NOT TRAVEL. `scopeSentence()` counts the SEND LOG —
   "1 campaign · 1 piece · 3 sends · Email" — which is the caption for the
   Performance report and a wrong statement about anybody else's list: three
   sends is not three rows on the approvals board. The chips say what is
   filtered wherever they stand; the section's own count says what came back. */
.mhp-scope.is-docked > .mhp-summary { display: none; }
.mhp-scope.is-docked > .mhp-picker-spacer { display: none; }

/* The separator has nothing to separate once the Report picker is a section
   dropdown standing to its left — it keeps its job, but the label after it
   carries the group, so it must not double up with the bar's own divider. */
.mhp-scope.is-docked > .mhp-fb-sep { min-height: 20px; }
