/* Campaigns › Messaging.
   The table itself is .ct-table from Call Logs, so this file only sizes the
   columns and styles the cells that are specific to a campaign. */

/* gpWrap is a flex column with a 14px gap and 18/24/32px padding, so each band
   was being spaced apart and inset. One wrapper absorbs both: it cancels the
   padding and takes the single gap, and the bands inside stack tight against
   each other the way Call Logs does — toolbar, table, pagination, nothing
   between them.

   Horizontal padding is re-applied per band, matching the pattern each screen
   already uses (#page-call-logs > .ct-pagination, #page-contacts .sk-panel >
   .ct-pagination) since the base classes only carry vertical values. */
.cmp-page{margin:-18px -24px -32px;display:flex;flex-direction:column;
  flex:1 1 auto;min-height:0}

.cmp-toolbar{padding:24px 24px 14px}
/* The pagination's border-top is the separator; the wrap's own bottom
   border sat directly against it and read as a double stroke. */
/* The table takes the leftover height so the pagination sits on the bottom of
   the page rather than under the last row — same as #page-call-logs. */
.cmp-wrap{border-left:0;border-right:0;border-bottom:0;border-radius:0;
  flex:1 1 auto;min-height:0;overflow:auto}
.cmp-pagination{padding:14px 24px;border-top:1px solid #F2F4F7;background:#fff;
  flex:0 0 auto}

.cmp-toolbar .ct-btn-ghost{display:inline-flex;align-items:center;gap:8px;white-space:nowrap}
.cmp-new{height:32px;display:inline-flex;align-items:center;gap:6px;white-space:nowrap}

/* Audience — a segment by name, or the size of a one-off list. */
/* Campaign, its channel and its step count in one cell — the channel is an
   icon because the word added nothing, and a drip is a glyph plus a number
   because "Drip · 3 steps" on every other row was noise. Both carry tooltips. */
/* Flex goes on this wrapper, not on the td. A td with display:flex stops
   contributing its height to the row and the rows drifted off Call Logs' 48px. */
.cmp-cell-row{display:flex;align-items:center;gap:10px;min-width:0}
.cmp-name-cell{min-width:0}
/* The channel is a tinted round disc, the same shape and size as the agent
   chips in Call Logs (.va-ic — 24px, border-radius 999px, tinted bg with a
   matching stroke glyph). Colours are lifted from VA_TONES rather than picked
   fresh, so the two tables share one palette.

   Only two tones, and only one of them is a colour. SMS is 11 of 16 rows — the
   default case, and announcing it sixteen times in colour is what would make
   the column loud. MMS is the exception and the one that changes cost and
   carrier handling, so it gets the tint.

   Teal specifically because this row already spends blue on the Recipients
   link, purple on the drip badge, and blue/amber/green/red/grey on the status
   dots. Teal is the only tone left that does not collide with a meaning the
   row already carries. */
.cmp-kind{flex:0 0 auto;display:inline-grid;place-items:center;
  width:24px;height:24px;border-radius:999px;cursor:default;
  background:#F2F4F7;color:#475467}
.cmp-kind.mms{background:#E0F7F4;color:#0E9384}
.cmp-kind svg{width:13px;height:13px;display:block}
.cmp-name{color:var(--text-primary);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cmp-steps{flex:0 0 auto;display:inline-flex;align-items:center;gap:3px;height:20px;
  padding:0 7px 0 5px;border-radius:7px;font-size:11px;font-weight:600;
  background:#F4F3FF;color:#5925DC;border:1px solid #E4DFFE;cursor:default}
.cmp-steps svg{width:11px;height:11px;flex:0 0 auto}

/* Edit / Analytics on row hover. Only the reveal is declared — .jc-quick and
   .jc-quick-btn come from Contacts, the same as the Dialer table. */
.cmp-table tbody tr:hover .jc-quick,
.cmp-name-cell:focus-within .jc-quick{opacity:1;transform:translateX(0);
  pointer-events:auto}

/* The audience is a link — it names a list you can go and look at. */
.cmp-col-aud{width:180px}
.cmp-aud-link{display:inline-flex;align-items:center;gap:6px;font-size:13px;
  color:var(--brand-blue);text-decoration:none;max-width:100%}
.cmp-aud-link svg{flex:0 0 auto;color:var(--brand-blue);opacity:.75}
.cmp-aud-link span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cmp-aud-link:hover span{text-decoration:underline}
.cmp-aud{white-space:nowrap}
.cmp-none{font-size:13px;color:var(--text-tertiary)}

.cmp-col-num{width:170px}
.cmp-col-date{width:210px}
.cmp-col-status{width:215px}

/* No padding of its own — restating it here is what pushed the rows to 58px
   against Call Logs' 48px. .ct-table already sets 8px 16px 8px 24px, and every
   cell below is capped at 26px so the row lands on 48px exactly. */
.cmp-table tbody td{vertical-align:middle}




/* JustCall number — the flag sits as a small avatar before the digits. */
.cmp-num{font-size:13px;color:var(--text-primary);white-space:nowrap}
/* Flat SVG flags, drawn edge to edge — see FLAG_SVG in campaigns-messaging.js
   for why an emoji cannot do this. The svg fills the box and the border-radius
   rounds it, so the flag reaches the rim on every side.

   A single light ring, no drop shadow. The dark hairline pressed the disc flat
   into the row; the shadow lifted it into a sticker. This sits between: enough
   edge to keep a white band off a white row, not enough to draw attention. */
.cmp-flag{display:inline-block;width:22px;height:22px;margin-right:10px;
  border-radius:999px;overflow:hidden;vertical-align:middle;flex:0 0 22px;
  line-height:0;box-shadow:0 0 0 1px rgba(16,24,40,.09)}
.cmp-flag svg{width:100%;height:100%;display:block}

/* Selecting a row does not tint it — Call Logs has no such rule in light mode,
   and the ticked checkbox is the indicator. */
.cmp-table .ct-td-check,
.cmp-table .ct-th-check{width:44px}
.cmp-col-name{min-width:200px}

/* Hidden actions must not leave a gap in the bar. */
#cmpBulkBar .bulk-bar-act[hidden]{display:none}

/* Delete is destructive, so it reads as such. The bar is #101828, so the light
   red carries against it where a mid red would not. */
#cmpBulkBar .bulk-bar-act[data-act="del"]{color:#FDA29B}
#cmpBulkBar .bulk-bar-act[data-act="del"] svg{color:#FDA29B}
#cmpBulkBar .bulk-bar-act[data-act="del"]:hover{background:rgba(240,68,56,.16);color:#FECDCA}
#cmpBulkBar .bulk-bar-act[data-act="del"]:hover svg{color:#FECDCA}

/* Created — date and author on one line, the author dimmed and separated by a
   dot. Stacked, it was the tallest cell in the row. */
.cmp-date{font-size:13px;font-weight:500;color:var(--text-primary);white-space:nowrap}
.cmp-date-sub{font-weight:400;color:var(--text-secondary)}
.cmp-date-sub::before{content:'·';margin:0 6px;color:var(--text-tertiary)}

/* Status — .ct-status, the dot-and-label component Call Logs' own Status column
   uses. It was a filled .ct-trait pill, which is the Traits component: it gave
   status the same weight as the drip badge and the To link, and three coloured
   pills per row made the column the loudest thing on screen.

   The label is a fixed width so every meter starts at the same x. Ragged pills
   put each bar at a different offset, which defeats the one thing a column of
   bars is for — being read down, against each other. */
.cmp-status-cell{white-space:nowrap}
/* No colour or type of its own — .ct-status carries those, so the label reads
   exactly as it does in Call Logs. Only the width is set here, for alignment. */
.cmp-st{flex:0 0 auto;min-width:74px}
.cmp-st .ct-status-dot{width:7px;height:7px;border-radius:50%;flex:0 0 7px;
  background:var(--text-tertiary)}

/* Blue is running now; the same blue hollow is scheduled to run. Solid grey is
   a draft — nothing is going to happen to it on its own. */
.cmp-st-running .ct-status-dot,
.cmp-st-sending .ct-status-dot{background:var(--brand-blue)}
.cmp-st-scheduled .ct-status-dot{background:#fff;box-shadow:inset 0 0 0 2px #84ADFF}
.cmp-st-paused .ct-status-dot{background:#F79009}
.cmp-st-done .ct-status-dot{background:#12B76A}
.cmp-st-stopped .ct-status-dot{background:#F04438}
.cmp-st-draft .ct-status-dot{background:#98A2B3}

.cmp-meter{flex:0 0 auto;display:inline-flex;align-items:center;gap:7px}
/* Secondary, not tertiary: this is the step you are actually on, and at 12px
   #98A2B3 sits near 2.6:1 on white — too faint to read a number from. */
.cmp-meter-n{font-size:12px;color:var(--text-secondary);white-space:nowrap;
  font-variant-numeric:tabular-nums}
.cmp-prog{flex:0 0 auto;display:block;width:56px;height:4px;border-radius:999px;
  background:var(--surface-panel);overflow:hidden}
.cmp-prog i{display:block;height:100%;border-radius:999px;background:var(--brand-blue)}
.cmp-prog.paused i{background:#F79009}
.cmp-prog.stopped i{background:#F04438}

/* ── Campaigns › Dialer ──────────────────────────────────────────────────────
   Shares the page shell above (.cmp-page/.cmp-toolbar/.cmp-wrap/.cmp-pagination)
   and the Call Logs table. Only the cells below are specific to a dialer
   campaign. Every one of them is a single line so the rows stay on .ct-table's
   48px, the same as Call Logs and the Messaging tab. */
/* Wider than the viewport on purpose, the way Contacts does it (min-width
   1520px there): the table scrolls rather than compressing to fit, and the last
   column sits off-screen until it is wanted.

   Every content column is the same 250px. Sizing each one to its own contents
   left the column edges at arbitrary intervals — 260, 250, 150, 150, 170 — so
   the gaps between headers read as ragged. Equal columns put those edges on a
   regular beat instead. The checkbox is excluded; it is a control, not a
   column of data. */
/* The ring is a fixed 26px where the bar was a 150px stretch, so the progress
   cell no longer needs a column of its own size — the grid goes back to even,
   which is where it reads best. */
.dc-table{min-width:1592px}
.dc-col-name,
.dc-col-prog,
.dc-col-rate,
.dc-col-to{width:290px}

/* Cell padding comes from the shared .ct-table rule. This table used to set
   36px of its own, which read as airier than every other table in the app for
   no reason a reader could see. */
.dc-table tbody td{vertical-align:middle}

/* The ID lives in the name's tooltip. It is a lookup key — you use it when you
   already have one to match, which is a search, not a thing you read down the
   column — so printing it on every row only greyed out half the cell. */
.dc-name{color:var(--text-primary);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;cursor:default}

/* Progress reads percentage, bar, then the raw count — one value, its picture,
   then the detail behind it. The percentage is fixed-width and tabular so the
   bars all start at the same x and the numbers line up on the decimal. */
/* Count and percentage on one line, bar beneath. Two lines, but the row keeps
   its 48px: .ct-table gives tbody td no vertical padding, so this 29px stack
   sits inside the height the row already reserves. (The Messaging table's
   Created cell did push rows to 58px when it stacked — that was a local
   padding-top/bottom:12px on top of the height, not the stacking itself.) */
.dc-prog{display:block}
.dc-prog-top{display:flex;align-items:baseline;justify-content:space-between;
  gap:12px;margin-bottom:6px}
/* Width only — the height comes from .cmp-prog, which is 4px everywhere else
   in the product. The 6px here was a local override, so dropping it both
   thins the bar and puts every bar in the product back on one height. */
.dc-bar{display:block;width:100%;border-radius:999px}
.dc-bar.full i{background:#12B76A}

/* Start appears on row hover, in .jc-quick — the hover-action component
   Contacts already uses on its name cell. Only the reveal is declared here;
   everything about the button itself comes from that component. */
.dc-table tbody tr:hover .jc-quick,
.dc-name-cell:focus-within .jc-quick{opacity:1;transform:translateX(0);
  pointer-events:auto}

/* Progress ring — kept as an available component, and demonstrated in the
   component reference, though the table currently uses the bar above. */
.dc-ring{flex:0 0 26px;width:26px;height:26px;display:block}
.dc-ring svg{width:100%;height:100%;display:block;transform:rotate(-90deg)}
.dc-ring circle{fill:none;stroke-width:3.4}
.dc-ring-t{stroke:var(--surface-panel)}
.dc-ring-f{stroke:var(--brand-blue);stroke-linecap:round}
/* A finished campaign reads green, and loses the cap so the join is seamless. */
.dc-ring.full .dc-ring-f{stroke:#12B76A;stroke-linecap:butt}
/* 38px, not 34: a campaign at 100% is four characters and nudged its bar 4px
   right of every other row's. */
/* No min-width now that the two numbers sit at opposite ends of the line —
   the percentage right-aligns to the bar's own right edge, so the column of
   percentages lines up without one being forced. */
/* The total is the same on most rows, so it recedes behind the count that
   actually changes. */
/* 12px. The cell is a count and a bar; at 13 the count was competing with
   the campaign name beside it. */
.dc-prog-n{flex:0 0 auto;font-size:12px;color:var(--text-secondary);
  white-space:nowrap;font-variant-numeric:tabular-nums}
.dc-prog-of{color:var(--text-tertiary)}

/* Queue chips are .cl-disp-chip from Call Logs; live calls take the green
   reading the tag palette already uses for a connected call. */
.dc-table .cl-disp-chip svg{width:13px;height:13px;flex:0 0 13px;opacity:.85}
.dc-chip-live{background:#ECFDF3;border-color:#D1FADF;color:#067647}
.dc-chip-live svg{color:#12B76A;opacity:1}

.dc-link{font-size:13px;font-weight:500;color:var(--brand-blue);text-decoration:none}
.dc-link:hover{text-decoration:underline}

/* Dialing mode — the campaign's kind, so it reads at the weight of an
   identity rather than of a measurement: primary ink, no chip. A chip on
   every row of a three-value column is eighteen boxes saying what plain
   words say. */
/* Plain text, a step below the campaign name beside it. The tag shape was
   chrome around one of three fixed words — the column heading already says
   what the word is, and the weight difference is enough to keep the name the
   thing you read first. */
.dc-col-mode{width:170px}
.dc-mode{color:var(--text-secondary);white-space:nowrap}

/* The row opens the campaign, so it looks and behaves like the control it
   is. The cells that are their own controls — the checkbox, the connect
   rate, the priority chip — keep their own click; see the note in
   campaigns-dialer.js. */
.dc-table tbody tr.is-open{cursor:pointer}
.dc-table tbody tr.is-open:focus-visible{outline:2px solid var(--brand-blue);
  outline-offset:-2px}
body.theme-dark .dc-mode{color:#D1D5DB}

/* Scoped to the stack, not to .dc-table: the markup is class="jc-avatar dc-ava"
   and .jc-avatar sets its own 28px, so these need to outrank it — but tying
   that to the table made the component unusable anywhere else, which the
   component reference caught the moment it rendered one outside a table.

   Assigned-to faces — .jc-avatar, the illustrated portrait Contacts uses, so a
   person looks the same wherever they appear. These are pictures rather than
   initials, so the stack can overlap properly: a face reads from a sliver, and
   nothing here has a second letter to clip. Earlier faces sit on top. */
.dc-ava-stack{display:inline-flex;align-items:center;cursor:default;
  padding-right:2px}
.dc-ava-stack .dc-ava{position:relative;width:26px;height:26px;flex:0 0 26px;
  border-radius:50%;overflow:hidden;box-shadow:0 0 0 1.5px #fff}
.dc-ava-stack .dc-ava svg{width:100%;height:100%;display:block}
.dc-ava + .dc-ava{margin-left:-8px}
.dc-ava:nth-child(1){z-index:4}
.dc-ava:nth-child(2){z-index:3}
.dc-ava:nth-child(3){z-index:2}
.dc-ava:nth-child(4){z-index:1}
.dc-ava-stack .dc-ava-more{background:#F2F4F7;color:var(--text-secondary);
  display:inline-grid;place-items:center;font:600 10px/1 'Inter',sans-serif}

#dcBulkBar .bulk-bar-act[hidden]{display:none}
#dcBulkBar .bulk-bar-act[data-act="del"]{color:#FDA29B}
#dcBulkBar .bulk-bar-act[data-act="del"] svg{color:#FDA29B}
#dcBulkBar .bulk-bar-act[data-act="del"]:hover{background:rgba(240,68,56,.16);color:#FECDCA}
#dcBulkBar .bulk-bar-act[data-act="del"]:hover svg{color:#FECDCA}


/* ── Recipients modal ────────────────────────────────────────────────────────
   Opened from the Recipients cell. Frame comes from .mx-page-modal-overlay /
   .mx-page-modal; only the contents are declared here. */
.cmp-rx{z-index:1200;background:rgba(16,24,40,.32);padding:24px;
  opacity:0;transition:opacity .18s ease}
.cmp-rx.show{opacity:1}
.cmp-rx-modal{width:520px;max-width:calc(100vw - 48px);
  max-height:min(560px,calc(100vh - 96px));display:flex;flex-direction:column;
  overflow:hidden;transform:translateY(8px) scale(.99);
  transition:transform .18s cubic-bezier(.32,.72,0,1)}
.cmp-rx.show .cmp-rx-modal{transform:none}

.cmp-rx-head{display:flex;align-items:flex-start;gap:11px;padding:18px 20px 15px;
  border-bottom:1px solid var(--border)}
.cmp-rx-ic{flex:0 0 30px;width:30px;height:30px;border-radius:8px;display:grid;
  place-items:center;background:var(--surface-panel);color:var(--text-secondary)}
.cmp-rx-t{flex:1 1 auto;min-width:0}
.cmp-rx-name{font-size:15px;font-weight:600;color:var(--text-primary);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cmp-rx-sub{margin-top:3px;font-size:12.5px;color:var(--text-secondary);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cmp-rx-x{flex:0 0 auto;width:28px;height:28px;border:0;border-radius:7px;
  background:transparent;color:var(--text-tertiary);display:grid;place-items:center;
  cursor:pointer;transition:background-color .14s,color .14s}
.cmp-rx-x:hover{background:var(--surface-panel);color:var(--text-primary)}

.cmp-rx-body{flex:1 1 auto;min-height:0;overflow:auto;padding:6px 0}
/* Same 48px rhythm as every table in the product. */
.cmp-rx-row{display:flex;align-items:center;gap:11px;height:48px;padding:0 20px}
.cmp-rx-row:hover{background:var(--surface-panel)}
.cmp-rx-av{flex:0 0 28px;width:28px;height:28px;border-radius:50%;overflow:hidden}
.cmp-rx-av svg{width:100%;height:100%;display:block}
.cmp-rx-nm{flex:1 1 auto;min-width:0;font-size:13px;font-weight:500;
  color:var(--text-primary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cmp-rx-ph{flex:0 0 auto;font-size:12.5px;color:var(--text-secondary);
  font-variant-numeric:tabular-nums;white-space:nowrap}
.cmp-rx-co{flex:0 0 96px;text-align:right;font-size:12.5px;color:var(--text-tertiary);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

.cmp-rx-foot{display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:12px 20px;border-top:1px solid var(--border);flex:0 0 auto}
.cmp-rx-more{font-size:12.5px;color:var(--text-secondary)}
.cmp-rx-all{height:30px;display:inline-flex;align-items:center;gap:6px}

@media (prefers-reduced-motion:reduce){
  .cmp-rx,.cmp-rx-modal{transition:none}
}

/* ── Dark mode ───────────────────────────────────────────────────────────────
   Everything on tokens flips by itself now (see tokens.css). What is left here
   is the literal hex that carries meaning rather than surface — a channel tint,
   a drip badge, a status colour — which has to be restated for dark because the
   light values are tuned for a white row and go luminous on a dark one. */

/* Channel disc. The light greys were the worst offenders: on a dark row they
   read as blown-out white circles. */
body.theme-dark .cmp-kind{background:#23262C;color:#9BA1AC}
body.theme-dark .cmp-kind.mms{background:#123A38;color:#5EDDD0}

/* Drip badge — same story, a near-white pill on every drip row. */
body.theme-dark .cmp-steps{background:#241F3D;color:#C4B5FD;border-color:#37306B}

/* Status dots: the hues hold up on dark, only the scheduled ring and the draft
   grey need lifting so they do not disappear into the row. */
body.theme-dark .cmp-st-scheduled .ct-status-dot{background:#191A1C;box-shadow:inset 0 0 0 2px #3E6BD1}
body.theme-dark .cmp-st-draft .ct-status-dot{background:#71767F}

/* Meter track. */
body.theme-dark .cmp-prog{background:#2A2D33}

/* Flag ring: a light hairline vanishes on dark, so it inverts to a faint light
   edge that keeps a white flag band off a dark row. */
body.theme-dark .cmp-flag{box-shadow:0 0 0 1px rgba(255,255,255,.14)}

/* Recipients modal. */
body.theme-dark .cmp-rx-ic{background:#23262C;color:#9BA1AC}
body.theme-dark .cmp-rx-row:hover{background:#1F2023}

/* Dialer: queue chips and the live dot. */
body.theme-dark .dc-chip-live{background:#0F2E22;border-color:#1C5B41;color:#5FD3A0}
body.theme-dark .dc-chip-live svg{color:#34D399}
body.theme-dark .dc-ava{box-shadow:0 0 0 1.5px #191A1C}
body.theme-dark .dc-ava-more{background:#23262C;color:#9BA1AC}

/* ── Recipients modal in dark mode ────────────────────────────────────────────
   Two things in the shared stack have to be answered here rather than by the
   tokens:

   1. .mx-page-modal hard-codes background:#FFFFFF (conversations.css), so the
      frame came out white on dark. The shell is used by Add Contact and the
      import wizard too, so it is fixed for this modal rather than swapped
      underneath everything.

   2. theme-customiser.css carries `body.theme-dark p, span, div, li …
      {color:inherit}`. At (0,1,2) that outweighs any single class, so every
      secondary and tertiary label in a dark modal collapsed to the primary
      text colour and the type hierarchy flattened. Restating them under
      body.theme-dark is what wins it back. */
body.theme-dark .cmp-rx-modal{background:var(--surface)}
body.theme-dark .cmp-rx-sub,
body.theme-dark .cmp-rx-ph,
body.theme-dark .cmp-rx-more{color:var(--text-secondary)}
body.theme-dark .cmp-rx-co{color:var(--text-tertiary)}
body.theme-dark .cmp-rx-nm{color:var(--text-primary)}

/* ═══ Top priority calls ══════════════════════════════════════════════════
   Which of a campaign's remaining contacts are worth dialling first. The chip
   is .cl-disp-chip, the same one the queue and upcoming counts next to it
   use — a new pill shape here would have made the two adjacent columns read
   as different kinds of number when they are the same kind.

   The dot carries the urgency, and it is the only thing that changes between
   levels: same chip, same type, same ground. Colour is doing one job, so it
   can be small.
   ────────────────────────────────────────────────────────────────────────── */
.dc-col-prio{width:190px}
.dc-prio{font-variant-numeric:tabular-nums;white-space:nowrap}
.dc-prio-dot{
  flex:0 0 7px;width:7px;height:7px;border-radius:50%;display:block;
}
.dc-prio-dot.is-hot{background:var(--error)}
.dc-prio-dot.is-warm{background:#F79009}
.dc-prio-dot.is-cool{background:var(--text-tertiary)}

/* Not a zero and not a dash. A campaign can have contacts left and none of
   them eligible to dial right now, which is a state worth saying in words —
   and saying without a chip, because there is no count to put in one. */
.dc-prio-none{
  display:inline-flex;align-items:center;gap:6px;
  font:400 13px/1.35 'Inter',sans-serif;color:var(--text-tertiary);white-space:nowrap;
}
.dc-prio-none svg{flex:0 0 14px;width:14px;height:14px;display:block}

/* The header's info mark sits on the text baseline, not centred on the cell —
   it belongs to the label. */
.dc-th-i{
  position:relative;display:inline-flex;align-items:center;margin-left:5px;
  color:var(--text-tertiary);vertical-align:-2px;outline:none;
}
.dc-th-i svg{width:13px;height:13px;display:block}
.dc-prio,.dc-prio-none{outline:none}

/* The breakdown, on hover or focus.

   A popover rather than the shared [data-jc-tip], which is plain text only —
   four labelled counts and a footnote need structure. Attached to <body> and
   positioned fixed, because the campaigns table scrolls horizontally on
   purpose and its wrapper would otherwise clip it. */
.dc-tp-pop{
  position:fixed;z-index:9600;width:260px;padding:14px 16px;
  background:#101828;color:#F4F4F5;border-radius:12px;
  box-shadow:0 16px 40px rgba(16,24,40,.34);
  opacity:0;pointer-events:none;transition:opacity .14s ease,transform .14s ease;
  transform:translateY(4px);text-align:left;white-space:normal;
}
.dc-tp-pop.show{opacity:1;transform:none}
/* The arrow tracks the cell, not the card — the card gets nudged to stay on
   screen at the first and last columns. */
.dc-tp-pop::after{
  content:'';position:absolute;top:100%;left:var(--dc-arrow,50%);transform:translateX(-50%);
  border:7px solid transparent;border-top-color:#101828;
}
.dc-tp-pop.below::after{
  top:auto;bottom:100%;border-top-color:transparent;border-bottom-color:#101828;
}
.dc-tp-h{display:block;font:600 14px/1.4 'Inter',sans-serif;margin-bottom:10px}
.dc-tp-pop.hdr .dc-tp-h{margin-bottom:0}
.dc-tp-row{display:flex;align-items:center;gap:9px;padding:5px 0}
.dc-tp-k{flex:1 1 auto;font:400 13px/1.4 'Inter',sans-serif;color:#D0D5DD}
.dc-tp-v{flex:0 0 auto;font:400 13px/1.4 'Inter',sans-serif;color:#F4F4F5;font-variant-numeric:tabular-nums}
.dc-tp-note{
  display:block;margin-top:10px;padding-top:10px;border-top:1px solid rgba(255,255,255,.14);
  font:400 12.5px/1.5 'Inter',sans-serif;color:#D0D5DD;
}
.dc-tp-note.bare{margin-top:0;padding-top:0;border-top:0}
.dc-tp-pop.hdr{font:400 12.5px/1.5 'Inter',sans-serif}
body.theme-dark .dc-tp-pop{background:#2A2D33;box-shadow:0 16px 40px rgba(0,0,0,.5)}
body.theme-dark .dc-tp-pop::after{border-top-color:#2A2D33}
body.theme-dark .dc-tp-pop.below::after{border-bottom-color:#2A2D33}

body.theme-dark .dc-prio-none,body.theme-dark .dc-th-i{color:var(--text-tertiary)}
body.theme-dark .dc-prio-dot.is-cool{background:var(--text-tertiary)}
