/*
 * contentagent admin styling.
 *
 * Scope: every rule below is a descendant of .contentagent-ui, which appears
 * only on contentagent's own templates. Nothing here can reach another Wagtail
 * screen. Wagtail's own component classes (.listing, .button, form controls)
 * are never targeted — the container is restyled, the controls are left alone.
 *
 * Theme: surface, text and rule colours come from Wagtail's design tokens, so
 * the screens follow whichever theme is active. Only the four semantic status
 * colours are literal, because Wagtail has no equivalent for them.
 *
 * No !important anywhere.
 */

.contentagent-ui {
  /* Structure, from Wagtail's tokens — follows the active theme. */
  --ca-surface: var(--w-color-surface-dashboard-panel);
  --ca-surface-head: var(--w-color-surface-field-inactive);
  --ca-border: var(--w-color-border-furniture);
  /* Four text levels, strongest first. Three come straight from Wagtail's
     own tokens; --ca-text-faint has no Wagtail equivalent (text-placeholder
     resolves to the same grey-400 as text-meta in light mode, so it gives no
     separation) and is derived with color-mix, with a value per theme. */
  --ca-text: var(--w-color-text-label);
  --ca-text-body: var(--w-color-text-context);
  --ca-text-meta: var(--w-color-text-meta);
  --ca-text-faint: color-mix(
    in srgb,
    var(--w-color-text-meta) 70%,
    var(--w-color-surface-page)
  );

  /* One spacing scale. Everything below uses these four steps. */
  --ca-space-1: 0.5rem;
  --ca-space-2: 0.75rem;
  --ca-space-3: 1.25rem;
  --ca-space-4: 2rem;

  /* Prose never runs wider than this. Tables and stat rows are exempt. */
  --ca-measure: 70ch;

  --ca-leading-body: 1.55;
  --ca-leading-heading: 1.25;
  --ca-radius: 10px;
  --ca-radius-sm: 7px;

  /* Light mode carries separation with a soft shadow. */
  --ca-shadow-resting: 0 1px 2px rgba(28, 26, 23, 0.04),
    0 1px 1px rgba(28, 26, 23, 0.03);
  --ca-shadow-raised: 0 4px 14px rgba(28, 26, 23, 0.08),
    0 1px 3px rgba(28, 26, 23, 0.05);

  /* The display serif. System stack — no web font, no external request. */
  --ca-font-display: ui-serif, Georgia, "Times New Roman", serif;

  /* Semantic status colours, taken literally from the prototype (light). */
  --ca-waiting-fg: #9c5700;
  --ca-waiting-bg: #fbeedd;
  --ca-waiting-br: #e6c79b;

  --ca-done-fg: #1f6b3b;
  --ca-done-bg: #e3f2e8;
  --ca-done-br: #a5cfb5;

  --ca-flagged-fg: #b3372c;
  --ca-flagged-bg: #fbe9e7;
  --ca-flagged-br: #e9b6af;

  --ca-running-fg: #1b5f94;
  --ca-running-bg: #e4eff7;
  --ca-running-br: #a8c8e0;

  color: var(--ca-text-body);
  line-height: var(--ca-leading-body);
}

/*
 * Dark variants. The prototype is light-only, so these are derived: the same
 * four hues held at a dark surface lightness with a light foreground, which
 * keeps the semantics readable against Wagtail's dark greys.
 */
.w-theme-dark .contentagent-ui {
  /* Mixing toward the page surface lightens in light mode and darkens in
     dark mode, which is the correct direction for "fainter" in both. */
  --ca-text-faint: color-mix(
    in srgb,
    var(--w-color-text-meta) 62%,
    var(--w-color-surface-page)
  );

  --ca-waiting-fg: #f0c079;
  --ca-waiting-bg: #3a2a12;
  --ca-waiting-br: #6b4c1f;

  --ca-done-fg: #86d3a3;
  --ca-done-bg: #14301f;
  --ca-done-br: #2c5c3c;

  --ca-flagged-fg: #f3a79c;
  --ca-flagged-bg: #3a1c18;
  --ca-flagged-br: #6e322a;

  --ca-running-fg: #8fc3e8;
  --ca-running-bg: #142a3c;
  --ca-running-br: #2b516f;

  /*
   * Shadows barely register on a dark surface, so they are dropped entirely
   * and the hairline border (--ca-border, from Wagtail's own token) carries
   * the separation instead. A card relying on the shadow would read flat here.
   */
  --ca-shadow-resting: none;
  --ca-shadow-raised: none;
}

@media (prefers-color-scheme: dark) {
  .w-theme-system .contentagent-ui {
    --ca-text-faint: color-mix(
      in srgb,
      var(--w-color-text-meta) 62%,
      var(--w-color-surface-page)
    );

    --ca-waiting-fg: #f0c079;
    --ca-waiting-bg: #3a2a12;
    --ca-waiting-br: #6b4c1f;

    --ca-done-fg: #86d3a3;
    --ca-done-bg: #14301f;
    --ca-done-br: #2c5c3c;

    --ca-flagged-fg: #f3a79c;
    --ca-flagged-bg: #3a1c18;
    --ca-flagged-br: #6e322a;

    --ca-running-fg: #8fc3e8;
    --ca-running-bg: #142a3c;
    --ca-running-br: #2b516f;

    --ca-shadow-resting: none;
    --ca-shadow-raised: none;
  }
}

/* ------------------------------------------------------------ typography */

/*
 * The one signature element: the page title, and nothing else. The wrapper is
 * display:contents so wrapping Wagtail's header changes no layout.
 * Section headings inside the page deliberately keep Wagtail's typeface —
 * using the serif twice would spend the contrast that makes it work.
 */
.contentagent-ui--chrome {
  display: contents;
}

.contentagent-ui .w-header__title {
  font-family: var(--ca-font-display);
  font-size: 1.375rem; /* Wagtail's default is 1.1875rem */
  letter-spacing: -0.015em;
}

/* ---------------------------------------------------------------- panels */

/* A heading and its panel. The heading sits on the page background, outside
   the bordered box, so a group costs a line of text rather than a 60px bar. */
.contentagent-ui .ca-block {
  margin-bottom: var(--ca-space-4);
}

.contentagent-ui .ca-panel {
  background-color: var(--ca-surface);
  border: 1px solid var(--ca-border);
  border-radius: var(--ca-radius);
  box-shadow: var(--ca-shadow-resting);
  margin-bottom: var(--ca-space-4);
  overflow: hidden;
}

.contentagent-ui .ca-block .ca-panel {
  margin-bottom: 0;
}

.contentagent-ui .ca-panel__head {
  display: flex;
  align-items: baseline;
  gap: var(--ca-space-2);
  padding: 0 0 var(--ca-space-1);
  background-color: transparent;
  border-bottom: 0;
}

.contentagent-ui .ca-panel__title {
  margin: 0;
  font-size: 0.75rem;
  font-weight: 600;
  line-height: var(--ca-leading-heading);
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--ca-text-meta);
}

.contentagent-ui .ca-panel__count {
  font-size: 0.75rem;
  font-variant-numeric: tabular-nums;
  color: var(--ca-text-faint);
}

.contentagent-ui .ca-panel__note {
  margin: 0 0 0 auto;
  max-width: var(--ca-measure);
  font-size: 0.75rem;
  line-height: var(--ca-leading-body);
  text-transform: none;
  letter-spacing: 0;
  color: var(--ca-text-faint);
}

.contentagent-ui .ca-panel__body {
  padding: var(--ca-space-3);
}

/* Air between the panel heading and whatever the panel opens with. */
.contentagent-ui .ca-panel__body > :first-child {
  margin-top: 0;
}

/* --------------------------------------------------------------- pills */

.contentagent-ui .ca-pill {
  display: inline-block;
  padding: 0.15rem 0.55rem;
  border: 1px solid transparent;
  border-radius: var(--ca-radius-sm);
  font-size: 0.8125rem;
  font-weight: 600;
  line-height: 1.5;
  white-space: nowrap;
}

.contentagent-ui .ca-pill--waiting {
  color: var(--ca-waiting-fg);
  background-color: var(--ca-waiting-bg);
  border-color: var(--ca-waiting-br);
}

/* An item that does not apply to this content type, or that the published
   page carries outside the body this score measures. Neither green nor red:
   it is not a result, it is the absence of a question. */
.contentagent-ui .ca-pill--muted {
  color: var(--ca-text-meta);
  background-color: transparent;
  border-color: var(--ca-border);
}

.contentagent-ui .ca-pill--done {
  color: var(--ca-done-fg);
  background-color: var(--ca-done-bg);
  border-color: var(--ca-done-br);
}

.contentagent-ui .ca-pill--flagged {
  color: var(--ca-flagged-fg);
  background-color: var(--ca-flagged-bg);
  border-color: var(--ca-flagged-br);
}

.contentagent-ui .ca-pill--running {
  color: var(--ca-running-fg);
  background-color: var(--ca-running-bg);
  border-color: var(--ca-running-br);
}

.contentagent-ui .ca-pill--neutral {
  color: var(--ca-text-meta);
  background-color: var(--ca-surface-head);
  border-color: var(--ca-border);
}

/* ------------------------------------------------------- misc helpers */

.contentagent-ui .ca-muted {
  color: var(--ca-text-meta);
}

.contentagent-ui .ca-faint {
  color: var(--ca-text-faint);
}

.contentagent-ui .ca-unbuilt {
  color: var(--ca-text-meta);
  font-style: italic;
}

.contentagent-ui .ca-meta {
  max-width: var(--ca-measure);
  margin: 0 0 var(--ca-space-3);
  font-size: 0.875rem;
  line-height: var(--ca-leading-body);
  color: var(--ca-text-meta);
}

.contentagent-ui .ca-actions {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.contentagent-ui .ca-actions form {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
}

/* A row of filter controls rather than a column of separate actions: same
   gap and wrapping as the form row above, laid out across instead of down. */
.contentagent-ui .ca-actions--filters {
  flex-direction: row;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-bottom: var(--ca-space-3);
}

.contentagent-ui .ca-preview {
  max-width: var(--ca-measure);
  line-height: var(--ca-leading-body);
  color: var(--ca-text-body);
}

/* A row of clickable starting points on an otherwise empty search screen. */
.contentagent-ui .ca-chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ca-space-1);
  margin-top: var(--ca-space-1);
}

.contentagent-ui .ca-chip {
  display: inline-flex;
  align-items: baseline;
  gap: 0.4rem;
  padding: 0.25rem 0.6rem;
  border: 1px solid var(--ca-border);
  border-radius: 999px;
  background: var(--ca-surface);
  color: var(--ca-text);
  font-size: 0.85rem;
  text-decoration: none;
}

.contentagent-ui .ca-chip:hover,
.contentagent-ui .ca-chip:focus-visible {
  border-color: var(--ca-text-meta);
  text-decoration: none;
}

.contentagent-ui .ca-chip__count {
  color: var(--ca-text-meta);
  font-size: 0.78rem;
}

/* A column header that carries an explainer button. */
.contentagent-ui .ca-th {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
}

/* The `?` beside a column header. A real button so it is focusable and
   announced; sized to sit on the header baseline without shifting it. */
.contentagent-ui .ca-help {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.15rem;
  height: 1.15rem;
  padding: 0;
  border: 1px solid var(--ca-border);
  border-radius: 50%;
  background: transparent;
  color: var(--ca-text-meta);
  font-size: 0.7rem;
  line-height: 1;
  cursor: help;
}

.contentagent-ui .ca-help:hover,
.contentagent-ui .ca-help:focus-visible {
  color: var(--ca-text);
  border-color: var(--ca-text-meta);
}

/* The reference band on the landing page. Quieter than the two above it:
   nothing in it is owed, so it should not compete with what is. */
.contentagent-ui .ca-block--quiet .ca-card {
  background: transparent;
}

.contentagent-ui .ca-block--quiet .ca-panel__title {
  color: var(--ca-text-meta);
}

/* A tile with nothing to show. The value slot keeps its height so the row of
   tiles does not jump, and the reason sits under the label. */
.contentagent-ui .ca-stat__value--none {
  color: transparent;
}

.contentagent-ui .ca-stat__note {
  display: block;
  font-size: 0.8rem;
  line-height: 1.3;
}

/* A value nobody measured. Italic grey, and the cell says which value.
   The principle is unchanged — we never print a zero we did not measure —
   but a bare dash reads as broken, and these columns are not broken. */
.contentagent-ui .ca-unmeasured {
  font-style: italic;
  color: var(--ca-text-faint);
}

/* An empty day on the calendar. Not an unmeasured value: a free day, which
   is a fact and not a gap, so it is quieter still and not italic. */
.contentagent-ui .ca-free {
  color: var(--ca-text-faint);
}

/* The one-line footnote under a table that carries unmeasured cells. */
.contentagent-ui .ca-footnote {
  margin-top: var(--ca-space-2);
  font-size: 0.85rem;
  color: var(--ca-text-meta);
  max-width: var(--ca-measure);
}

.contentagent-ui .ca-footnote em {
  font-style: italic;
  color: var(--ca-text-faint);
}

/* The calendar legend: what each mark on the grid means. */
.contentagent-ui .ca-legend {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--ca-space-2);
  margin-top: var(--ca-space-2);
  font-size: 0.85rem;
  color: var(--ca-text-meta);
}

.contentagent-ui .ca-legend__note {
  flex-basis: 100%;
  color: var(--ca-text-meta);
}

/* The standfirst on the patterns screen: what this page is, before any
   numbers. Constrained to the reading measure like body prose. */
.contentagent-ui .ca-standfirst {
  max-width: var(--ca-measure);
  margin-bottom: var(--ca-space-3);
}

/* A before/after verdict on a patterns row. Colour carries the direction, and
   the sentence says it in words too, so colour is never the only signal. */
.contentagent-ui .ca-trend {
  display: block;
  margin-top: 0.25rem;
}

.contentagent-ui .ca-trend--improved {
  color: var(--ca-done-fg);
}

.contentagent-ui .ca-trend--worse {
  color: var(--ca-flagged-fg);
  font-weight: 600;
}

/* The finished text of a run that has no page, offered for copying out.
   Readonly and monospaced: this is source to paste into LinkedIn, Brevo or a
   host's CMS, not prose to read — the rendered version sits above it. */
.contentagent-ui .ca-source {
  width: 100%;
  font-family: var(--w-font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: 0.85rem;
  line-height: 1.5;
  padding: 0.5rem;
  border: 1px solid var(--ca-border, currentColor);
  border-radius: 4px;
  background: var(--ca-surface, transparent);
  color: var(--ca-text-body);
  resize: vertical;
}

.contentagent-ui .ca-kv {
  width: 100%;
  border-collapse: collapse;
}

.contentagent-ui .ca-kv th,
.contentagent-ui .ca-kv td {
  padding: var(--ca-space-1) var(--ca-space-3) var(--ca-space-1) 0;
  text-align: left;
  vertical-align: top;
  border-bottom: 1px solid var(--ca-border);
  font-weight: 400;
}

.contentagent-ui .ca-kv tr:last-child th,
.contentagent-ui .ca-kv tr:last-child td {
  border-bottom: 0;
}

.contentagent-ui .ca-kv th {
  width: 16rem;
  color: var(--ca-text-meta);
}

.contentagent-ui .ca-nowrap {
  white-space: nowrap;
}

/* ---------------------------------------------------------- nav cards */

.contentagent-ui .ca-cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(17rem, 1fr));
  gap: var(--ca-space-2);
}

.contentagent-ui .ca-card {
  display: block;
  padding: var(--ca-space-2) var(--ca-space-3);
  background-color: var(--ca-surface);
  border: 1px solid var(--ca-border);
  border-radius: var(--ca-radius);
  box-shadow: var(--ca-shadow-resting);
  color: inherit;
  text-decoration: none;
}

.contentagent-ui a.ca-card:hover {
  box-shadow: var(--ca-shadow-raised);
  border-color: var(--w-color-border-furniture-more-contrast);
}

.contentagent-ui .ca-card__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  margin-bottom: 0.5rem;
}

.contentagent-ui .ca-card__label {
  font-weight: 600;
}

.contentagent-ui .ca-card__desc {
  max-width: var(--ca-measure);
  margin: 0;
  /* A failed run's recorded reason can carry a long unbroken URL. */
  overflow-wrap: anywhere;
  font-size: 0.875rem;
  line-height: var(--ca-leading-body);
  color: var(--ca-text-meta);
}

.contentagent-ui .ca-card--unbuilt {
  border-style: dashed;
  box-shadow: none;
}

/* ----------------------------------------------------------- calendar */

.contentagent-ui .ca-calendar {
  width: 100%;
  table-layout: fixed;
  border-collapse: collapse;
}

.contentagent-ui .ca-calendar th {
  padding: 0.5rem 0.25rem;
  font-size: 0.75rem;
  font-weight: 600;
  text-align: left;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ca-text-meta);
  border-bottom: 1px solid var(--ca-border);
}

.contentagent-ui .ca-day {
  height: 7rem;
  padding: 0.4rem;
  vertical-align: top;
  border: 1px solid var(--ca-border);
  border-radius: var(--ca-radius-sm);
}

.contentagent-ui .ca-day--outside .ca-day__num {
  color: var(--ca-text-meta);
  opacity: 0.6;
}

/* Saturday and Sunday. Dimmed, because nothing is scheduled to start on one
   and a reader scanning for a free weekday should not have to exclude them. */
.contentagent-ui .ca-day--weekend {
  background-color: var(--ca-surface-head);
}

.contentagent-ui .ca-day--weekend .ca-day__num {
  opacity: 0.7;
}

.contentagent-ui .ca-day--today {
  border-color: var(--w-color-border-furniture-more-contrast);
  background-color: var(--ca-surface-head);
}

.contentagent-ui .ca-day__num {
  display: block;
  margin-bottom: 0.35rem;
  font-size: 0.8125rem;
  font-variant-numeric: tabular-nums;
  color: var(--ca-text-meta);
}

.contentagent-ui .ca-day__item {
  margin-bottom: 0.4rem;
  padding: 0.35rem 0.4rem;
  font-size: 0.8125rem;
  line-height: 1.4;
  background-color: var(--ca-surface);
  border: 1px solid var(--ca-border);
  border-radius: var(--ca-radius-sm);
}

.contentagent-ui .ca-day__item form {
  margin-top: 0.3rem;
}

/* ------------------------------------------------- page head / lead / note */

.contentagent-ui .ca-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--ca-space-3);
  margin-bottom: var(--ca-space-4);
  flex-wrap: wrap;
}

.contentagent-ui .ca-head__lead {
  max-width: var(--ca-measure);
  margin: 0;
  font-size: 0.9375rem;
  line-height: var(--ca-leading-body);
  color: var(--ca-text-body);
}

.contentagent-ui .ca-head__actions {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
  margin-left: auto;
}

/* A button that is not built yet, with the reason beside it rather than in a
   title attribute nobody sees (build 60). The reason stacks under the label so
   the header keeps its row of buttons. */
.contentagent-ui .ca-head__unbuilt {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.15rem;
  max-width: 22rem;
}

.contentagent-ui .ca-head__unbuilt .ca-sub {
  text-align: right;
  line-height: 1.35;
}

.contentagent-ui .ca-note {
  max-width: var(--ca-measure);
  margin: 0 0 var(--ca-space-4);
  padding-top: var(--ca-space-3);
  border-top: 1px solid var(--ca-border);
}

.contentagent-ui .ca-note__title {
  margin: 0 0 0.35rem;
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--ca-text-meta);
}

.contentagent-ui .ca-note__body {
  max-width: var(--ca-measure);
  margin: 0;
  font-size: 0.875rem;
  line-height: var(--ca-leading-body);
  color: var(--ca-text-faint);
}

/* Wagtail's own help block, capped to the measure on our screens only. */
.contentagent-ui .help-block {
  max-width: var(--ca-measure);
}

.contentagent-ui .ca-prose {
  max-width: var(--ca-measure);
  line-height: var(--ca-leading-body);
  color: var(--ca-text-body);
}

/* ------------------------------------------------------------- stat tiles */

.contentagent-ui .ca-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: var(--ca-space-3);
  margin-bottom: var(--ca-space-4);
}

.contentagent-ui .ca-stat {
  padding: var(--ca-space-3);
  background-color: var(--ca-surface);
  border: 1px solid var(--ca-border);
  border-radius: var(--ca-radius);
  box-shadow: var(--ca-shadow-resting);
}

.contentagent-ui .ca-stat__value {
  display: block;
  font-family: var(--ca-font-display);
  font-size: 2rem;
  line-height: var(--ca-leading-heading);
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  color: var(--ca-text);
}

.contentagent-ui .ca-stat__label {
  display: block;
  margin-top: var(--ca-space-1);
  font-size: 0.8125rem;
  line-height: var(--ca-leading-heading);
  white-space: nowrap;
  color: var(--ca-text-meta);
}

/* -------------------------------------------------------- stage tracker */

/* A bar across, not a column down. Ten stages stacked ran ~480px tall and
   pushed the draft — the thing a person opens this screen for — below the
   fold. Each stage is a segment; only the current one is labelled, because
   ten labels across is unreadable and the other nine are answered by colour. */
.contentagent-ui .ca-stages {
  display: flex;
  gap: 0.25rem;
  align-items: stretch;
}

.contentagent-ui .ca-stage {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  padding: 0.4rem 0.5rem;
  border: 1px solid transparent;
  border-top: 3px solid var(--ca-border);
  border-radius: var(--ca-radius-sm);
}

.contentagent-ui .ca-stage--done {
  border-top-color: var(--ca-done-fg);
}

.contentagent-ui .ca-stage--current {
  border-top-color: var(--ca-running-fg);
}

/* A step the run passes without anything happening in it: dashed and faded,
   so it never reads as pending or as done. The reason is in the tooltip. */
.contentagent-ui .ca-stage--skipped {
  border-top-style: dashed;
  opacity: 0.45;
}

/* Where a failed or stopped run ended. Named like the current stage, in the
   flagged colour, so the bar says how far it got instead of showing nothing. */
.contentagent-ui .ca-stage--ended {
  border-color: var(--ca-border);
  border-top-color: var(--ca-flagged-fg);
  background-color: var(--ca-surface-head);
}

.contentagent-ui .ca-stage--ended .ca-stage__label {
  font-weight: 600;
}

.contentagent-ui .ca-stage--ended .ca-stage__note {
  color: var(--ca-flagged-fg);
}

/* Only the current stage names itself, or the one a run ended at; the rest
   are a number and a colour. */
.contentagent-ui .ca-stage:not(.ca-stage--current):not(.ca-stage--ended) .ca-stage__label,
.contentagent-ui .ca-stage:not(.ca-stage--current):not(.ca-stage--ended) .ca-stage__note {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.contentagent-ui .ca-stage__label {
  font-size: 0.8125rem;
  line-height: 1.2;
}

.contentagent-ui .ca-stages__live {
  margin-top: var(--ca-space-1);
}

.contentagent-ui .ca-stage__num {
  font-variant-numeric: tabular-nums;
  font-size: 0.8125rem;
  color: var(--ca-text-meta);
}

.contentagent-ui .ca-stage--done .ca-stage__label {
  color: var(--ca-text-meta);
}

.contentagent-ui .ca-stage--current {
  background-color: var(--ca-surface-head);
  border-color: var(--ca-border);
}

.contentagent-ui .ca-stage--current .ca-stage__label {
  font-weight: 600;
}

.contentagent-ui .ca-stage--todo .ca-stage__num,
.contentagent-ui .ca-stage--todo .ca-stage__label {
  opacity: 0.55;
}

.contentagent-ui .ca-stage__note {
  font-size: 0.8125rem;
  color: var(--ca-text-meta);
}

/* --------------------------------------------------------- misc blocks */

.contentagent-ui .ca-row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--ca-space-3);
  padding: 0.85rem 0;
  border-bottom: 1px solid var(--ca-border);
}

.contentagent-ui .ca-row:last-child {
  border-bottom: 0;
}

.contentagent-ui .ca-row__title {
  font-weight: 600;
  line-height: var(--ca-leading-heading);
  color: var(--ca-text);
}

.contentagent-ui .ca-row__need {
  max-width: var(--ca-measure);
  margin: 0.2rem 0 0;
  font-size: 0.875rem;
  line-height: var(--ca-leading-body);
  color: var(--ca-text-meta);
}

.contentagent-ui .ca-row__side {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-shrink: 0;
}

.contentagent-ui .ca-sub {
  display: block;
  margin-top: 0.2rem;
  font-size: 0.8125rem;
  line-height: var(--ca-leading-body);
  color: var(--ca-text-faint);
}

/* ---------------------------------------------------- newsletter candidates */

.contentagent-ui .ca-candidate {
  padding: var(--ca-space-3) 0;
  border-bottom: 1px solid var(--ca-border);
}

.contentagent-ui .ca-candidate:last-child {
  border-bottom: 0;
  padding-bottom: 0;
}

.contentagent-ui .ca-candidate__head {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-bottom: 0.4rem;
}

.contentagent-ui .ca-candidate__angle {
  margin: 0 0 0.5rem;
  font-size: 0.9375rem;
  line-height: 1.5;
}

.contentagent-ui .ca-candidate__claims {
  margin: 0 0 0.5rem;
  padding-left: var(--ca-space-3);
  font-size: 0.875rem;
  line-height: 1.6;
  color: var(--ca-text-meta);
}

.contentagent-ui .ca-candidate__sources {
  margin: 0 0 0.6rem;
  font-size: 0.8125rem;
  color: var(--ca-text-meta);
}

.contentagent-ui .ca-candidate__actions {
  display: flex;
  gap: 0.5rem;
}

.contentagent-ui .ca-subhead {
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.contentagent-ui .ca-matrix td {
  vertical-align: top;
}

/* ------------------------------------------------- outline / decide forms */

.contentagent-ui .ca-outline {
  margin: 0;
  padding-left: var(--ca-space-3);
  line-height: 1.7;
}

/* Build 74, C24. The outline is a tree, so it is indented like one and each
   heading says its own level. An asset planned on a node is a chip beside it:
   a comparison table named here is one the draft is checked for. */
.contentagent-ui .ca-outline--tree {
  list-style: none;
  padding-left: 0;
}

.contentagent-ui .ca-outline__node--h3 { padding-left: var(--ca-space-4); }
.contentagent-ui .ca-outline__node--h4 { padding-left: calc(var(--ca-space-4) * 2); }

.contentagent-ui .ca-outline__level {
  display: inline-block;
  min-width: 2.1em;
  font-size: 0.7rem;
  font-weight: 700;
  color: var(--ca-text-meta);
}

.contentagent-ui .ca-outline__asset {
  display: inline-block;
  margin-left: 0.4rem;
  padding: 0 0.4em;
  border-radius: 3px;
  background: var(--ca-surface-sunken, #eef1f4);
  font-size: 0.7rem;
  font-weight: 600;
  color: var(--ca-text-meta);
}

.contentagent-ui .ca-field {
  display: block;
  margin-bottom: 0.5rem;
}

.contentagent-ui .ca-field__label {
  display: block;
  margin-bottom: 0.2rem;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--ca-text-meta);
}

.contentagent-ui .ca-decide {
  display: block;
  min-width: 18rem;
  margin-bottom: 0.9rem;
  padding-bottom: 0.9rem;
  border-bottom: 1px solid var(--ca-border);
}

.contentagent-ui .ca-decide:last-child {
  border-bottom: 0;
  padding-bottom: 0;
}

.contentagent-ui .ca-settings {
  margin: 0.4rem 0 0.6rem;
  font-size: 0.8125rem;
}

.contentagent-ui .ca-settings summary {
  cursor: pointer;
  color: var(--ca-text-meta);
}

/* ---------------------------------------------------------- keyword set */

.contentagent-ui .ca-kwset {
  min-width: 34rem;
  margin-bottom: var(--ca-space-3);
  padding-bottom: 0.9rem;
  border-bottom: 1px solid var(--ca-border);
}

.contentagent-ui .ca-kwtable {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.8125rem;
}

.contentagent-ui .ca-kwtable th {
  padding: 0.25rem 0.5rem 0.25rem 0;
  font-size: 0.6875rem;
  font-weight: 600;
  text-align: left;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ca-text-meta);
  border-bottom: 1px solid var(--ca-border);
}

.contentagent-ui .ca-kwtable td {
  padding: 0.3rem 0.5rem 0.3rem 0;
  vertical-align: middle;
  border-bottom: 1px solid var(--ca-border);
}

.contentagent-ui .ca-kw--unused td {
  opacity: 0.6;
}

.contentagent-ui .ca-inline {
  display: flex;
  align-items: center;
  gap: 0.3rem;
  /* Wrap only when the viewport genuinely cannot hold the row. Without this a
     row that overflows just overflows; with it, and with the bases below, it
     breaks at a sensible point instead. */
  flex-wrap: wrap;
}

/* Wagtail's admin stylesheet sets `width: 100%` on form fields. Inside a flex
   row that makes every field claim the whole line, so each one lands on a line
   of its own and the "inline" row becomes a stack — which is what happened to
   the calendar's schedule box, where an eight-character date field rendered
   1518px wide.
   `.ca-inline` said `flex-direction: row` and was obeyed; what it never said
   was how wide its children should be. A rule that is incomplete fails as
   silently as one that is missing, and nothing catches either. */
.contentagent-ui .ca-inline > input,
.contentagent-ui .ca-inline > select,
.contentagent-ui .ca-inline > button {
  width: auto;
}

/* Sized to what each field actually holds. */
.contentagent-ui .ca-inline > input[type="date"] {
  flex: 0 0 auto;
  width: 10rem;
}

.contentagent-ui .ca-inline > input[type="search"],
.contentagent-ui .ca-inline > input[type="text"] {
  /* The one field that should take the slack: a search box or a reason. */
  flex: 1 1 18rem;
  min-width: 10rem;
}

.contentagent-ui .ca-inline > select {
  /* Wide enough for a long topic title, capped so one option cannot push the
     button off the row. */
  flex: 0 1 26rem;
  min-width: 10rem;
}

.contentagent-ui .ca-inline > button {
  flex: 0 0 auto;
  white-space: nowrap;
}

.contentagent-ui .ca-kwset__add {
  margin-top: 0.6rem;
}

.contentagent-ui .ca-kwset__rationale,
.contentagent-ui .ca-kwset__empty {
  margin: 0.5rem 0 0;
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--ca-text-meta);
}

/* ------------------------------------------------------ table readability
 *
 * Rules, applied to every contentagent table:
 *   - text columns get a min-width so a cell never wraps to one or two words
 *     per line; a title column never drops below 200px
 *   - long text truncates with an ellipsis and a title attribute rather than
 *     stacking vertically
 *   - numeric columns are narrow and right-aligned; text columns take the rest
 *   - if the columns cannot fit, the table scrolls rather than crushing
 */

.contentagent-ui .ca-panel__body {
  overflow-x: auto;
}

.contentagent-ui table.listing,
.contentagent-ui table.ca-table {
  table-layout: auto;
  min-width: 100%;
}

.contentagent-ui .ca-col-title {
  min-width: 200px;
}

.contentagent-ui .ca-col-text {
  min-width: 140px;
}

.contentagent-ui .ca-col-reason {
  min-width: 240px;
}

.contentagent-ui .ca-col-tag {
  min-width: 96px;
  white-space: nowrap;
}

.contentagent-ui .ca-col-when,
.contentagent-ui .ca-col-week {
  min-width: 130px;
  white-space: nowrap;
}

.contentagent-ui .ca-col-num {
  width: 1%;
  min-width: 72px;
  text-align: right;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.contentagent-ui .ca-col-decide,
.contentagent-ui .ca-col-set {
  width: 1%;
  min-width: 190px;
  white-space: nowrap;
}

.contentagent-ui .ca-truncate {
  display: block;
  max-width: 34rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The queue's quick actions — two links and a single submit, nothing more. */

.contentagent-ui .ca-quick {
  display: flex;
  align-items: center;
  gap: 0.4rem;
}

.contentagent-ui .ca-quick form {
  display: inline;
}

.contentagent-ui .ca-quick__edit {
  margin-left: 0.15rem;
  font-size: 0.8125rem;
}

.contentagent-ui .ca-quick__flag {
  display: inline-block;
  margin-top: 0.35rem;
}

/* Detail-page layout — full width sections, not squeezed cells. */

.contentagent-ui .ca-field--wide input,
.contentagent-ui .ca-field--wide textarea {
  width: 100%;
  max-width: 46rem;
}

.contentagent-ui .ca-settinggrid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  gap: 0.75rem 1.25rem;
  max-width: 60rem;
}

.contentagent-ui .ca-rolegrid {
  display: grid;
  gap: 0.5rem;
}

.contentagent-ui .ca-roleform {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.contentagent-ui .ca-roleform__term {
  flex: 0 0 22rem;
  max-width: 22rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 0.875rem;
}

.contentagent-ui .ca-setrole {
  font-size: 0.8125rem;
}

/* --------------------------------------------- landing card counts (5e) */

/* A plain numeral in the strongest text level. It only takes a status colour
   when the number means something is owed — a volume count stays neutral. */
.contentagent-ui .ca-count {
  font-family: var(--ca-font-display);
  font-size: 1.375rem;
  line-height: var(--ca-leading-heading);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
  color: var(--ca-text);
}

.contentagent-ui .ca-count--waiting {
  color: var(--ca-waiting-fg);
}

.contentagent-ui .ca-count--running {
  color: var(--ca-running-fg);
}

/* The remaining three tones _card can be passed. Only waiting and running were
   ever used, so the other three had no rule and would have rendered a count in
   the plain text colour with no warning. A tone is a closed set; every member
   of it gets a rule. */
.contentagent-ui .ca-count--done {
  color: var(--ca-done-fg);
}

.contentagent-ui .ca-count--flagged {
  color: var(--ca-flagged-fg);
}

.contentagent-ui .ca-count--neutral {
  color: var(--ca-text-meta);
}

/* ------------------------------------- one-line Decide column (5a) */

.contentagent-ui .ca-quick {
  display: flex;
  align-items: center;
  gap: var(--ca-space-1);
  white-space: nowrap;
}

.contentagent-ui .ca-more {
  position: relative;
}

.contentagent-ui .ca-more > summary {
  list-style: none;
  cursor: pointer;
  padding: 0 var(--ca-space-1);
  font-size: 1rem;
  line-height: 1.6;
  color: var(--ca-text-meta);
}

.contentagent-ui .ca-more > summary::-webkit-details-marker {
  display: none;
}

.contentagent-ui .ca-more__panel {
  position: absolute;
  right: 0;
  z-index: 5;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--ca-space-1);
  min-width: 11rem;
  padding: var(--ca-space-2);
  background-color: var(--ca-surface);
  border: 1px solid var(--ca-border);
  border-radius: var(--ca-radius);
  box-shadow: var(--ca-shadow-raised);
  white-space: nowrap;
}

/* ------------------------------------------------------------- new piece
 *
 * The originate-a-piece form. Colours come from the tokens at the top of this
 * file, which are redefined per theme, so these rules carry light and dark
 * without repeating themselves.
 */

.contentagent-ui .ca-newpiece {
  max-width: 46rem;
}

.contentagent-ui .ca-newpiece .ca-field {
  margin-bottom: var(--ca-space-3);
}

.contentagent-ui .ca-newpiece select {
  max-width: 46rem;
}

.contentagent-ui .ca-newpiece__help {
  max-width: var(--ca-measure);
  margin: 0.3rem 0 0;
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--ca-text-meta);
}

.contentagent-ui .ca-newpiece__errors {
  margin-bottom: var(--ca-space-3);
}

.contentagent-ui .ca-newpiece__when {
  padding: 0;
  border: 0;
}

.contentagent-ui .ca-newpiece__radios {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ca-space-3);
  align-items: center;
}

.contentagent-ui .ca-newpiece__radio {
  display: inline-flex;
  gap: 0.4rem;
  align-items: center;
  font-size: 0.875rem;
  color: var(--ca-text-body);
}

.contentagent-ui .ca-newpiece__radio input {
  margin: 0;
}

.contentagent-ui .ca-newpiece__submit {
  display: flex;
  gap: var(--ca-space-1);
  align-items: center;
  padding-top: var(--ca-space-2);
  border-top: 1px solid var(--ca-border);
}

/* ---------------------------------------------------------------------------
 * The outline gate's validation banner.
 *
 * Deliberately the loudest thing on the screen and placed above the plan. The
 * failure it reports already existed on run 26 — the Strategist flagged
 * "0 sources; the rules ask for 3-5" — but it appeared only in the timeline
 * underneath, so the outline was approved and six blocking findings followed.
 * A check the system has already run has to be visible where the decision is
 * taken, not one scroll below it.
 *
 * Colours reuse the existing --ca-flagged-* tokens, which are already defined
 * for the dark themes further up, so this needs no theme block of its own.
 * ------------------------------------------------------------------------ */
.contentagent-ui .ca-flagged {
  margin-bottom: var(--ca-space-4);
  padding: var(--ca-space-3);
  border: 1px solid var(--ca-flagged-br);
  border-left-width: 4px;
  border-radius: var(--ca-radius);
  background: var(--ca-flagged-bg);
  color: var(--ca-flagged-fg);
}

.contentagent-ui .ca-flagged__title {
  margin: 0 0 var(--ca-space-2);
  font-size: 1.05rem;
  color: var(--ca-flagged-fg);
}

.contentagent-ui .ca-flagged__list {
  margin: 0 0 var(--ca-space-2);
  padding-left: var(--ca-space-4);
}

.contentagent-ui .ca-flagged__list li {
  margin-bottom: var(--ca-space-1);
}

.contentagent-ui .ca-flagged__hint {
  margin: 0 0 var(--ca-space-3);
  color: var(--ca-text-body);
  font-size: 0.9rem;
}

/* The response sits inside the banner: the problem and the action for it in
   one place, rather than asking someone to find the form further down. */
.contentagent-ui .ca-flagged__form {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ca-space-2);
  align-items: center;
}

.contentagent-ui .ca-flagged__form input[type="text"] {
  flex: 1 1 22rem;
  min-width: 0;
}

.contentagent-ui .ca-subhead {
  margin: var(--ca-space-4) 0 var(--ca-space-2);
  font-size: 0.95rem;
  color: var(--ca-text-meta);
}

/* Long source URLs must wrap inside the cell instead of widening the table. */
.contentagent-ui .ca-break {
  overflow-wrap: anywhere;
  word-break: break-word;
  max-width: 28rem;
}

/* A page action that posts. The form is only there to carry the CSRF token
   and the method; it must sit in the action row exactly like the buttons and
   links beside it, not open a block of its own. */
.contentagent-ui .ca-head__form {
  display: inline;
  margin: 0;
}

/* The type chooser inside "Ask for 5 more" (build 69).
 *
 * It is part of the POST, not a filter beside it, so it has to sit in the same
 * form as the button without breaking the header's row of buttons: the label
 * and its select stack, the button stays on the line, and the sentence saying
 * what each type has actually returned wraps underneath the pair. Right
 * aligned, like `.ca-head__unbuilt`, because the whole action group is. */
.contentagent-ui .ca-head__form:has(.ca-head__choice) {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: flex-end;
  gap: 0.5rem;
  max-width: 30rem;
}

.contentagent-ui .ca-head__choice {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}

.contentagent-ui .ca-head__choice select {
  padding: 0.25rem 0.5rem;
  font-size: 0.85rem;
}

.contentagent-ui .ca-head__note {
  flex-basis: 100%;
  text-align: right;
  line-height: 1.35;
}

/* Final review: the draft and what was checked, side by side.

   The checks used to sit in a card below the draft, which on a 2,700-word
   article is three screens down from the thing being checked. A reader who
   scrolled past the draft to reach the decision never passed them. Beside the
   draft they are in view while the draft is being read, which is when they
   are worth anything.

   One column below 62rem: the aside is narrow enough that stacking it reads
   fine, and a two-column layout on a phone would leave the draft at 40% of a
   small screen. */
.contentagent-ui .ca-split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 19rem);
  gap: var(--ca-space-3);
  align-items: start;
}

@media (max-width: 62rem) {
  .contentagent-ui .ca-split {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* Sticky so the checks stay level with whatever paragraph is being read.
   `top` clears Wagtail's header; `max-height` plus its own scroll keeps a long
   list from running off a short viewport. */
.contentagent-ui .ca-split__aside {
  position: sticky;
  top: var(--ca-space-3);
  max-height: calc(100vh - 6rem);
  overflow-y: auto;
}

@media (max-width: 62rem) {
  .contentagent-ui .ca-split__aside {
    position: static;
    max-height: none;
  }
}

.contentagent-ui .ca-checks {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--ca-space-2);
}

.contentagent-ui .ca-check {
  display: grid;
  grid-template-columns: 1.25rem minmax(0, 1fr);
  gap: 0 var(--ca-space-1);
}

/* The tick or cross carries the outcome for anyone scanning; the words carry
   it for everyone else. Neither is the only signal. */
.contentagent-ui .ca-check__mark {
  font-size: 0.95rem;
  line-height: 1.45;
}

.contentagent-ui .ca-check--done .ca-check__mark {
  color: var(--ca-done-fg);
}

.contentagent-ui .ca-check--flagged .ca-check__mark {
  color: var(--ca-flagged-fg);
}

.contentagent-ui .ca-check__label {
  font-weight: 600;
  font-size: 0.875rem;
  color: var(--ca-text);
  line-height: 1.45;
}

.contentagent-ui .ca-check__outcome {
  grid-column: 2;
  font-size: 0.8125rem;
  color: var(--ca-text-meta);
  line-height: var(--ca-leading-body);
}

/* The duplicate check's worst pairs: the shared wording first, because that
   is what a person fixes, then the two headings it sits under. */
.contentagent-ui .ca-check__repeats {
  grid-column: 2;
  list-style: none;
  margin: var(--ca-space-1) 0 0;
  padding: 0;
  display: grid;
  gap: var(--ca-space-1);
}

.contentagent-ui .ca-check__repeat {
  padding-left: var(--ca-space-1);
  border-left: 2px solid var(--ca-border);
  overflow-wrap: anywhere;
}

.contentagent-ui .ca-check__said {
  display: block;
  font-size: 0.8125rem;
  color: var(--ca-text);
  line-height: var(--ca-leading-body);
}

.contentagent-ui .ca-check__where {
  display: block;
  font-size: 0.75rem;
  color: var(--ca-text-meta);
  line-height: var(--ca-leading-body);
}

/* Findings the editor could not resolve. Not a blocker, so not styled as one:
   a flat list under a quiet heading, with the reader told plainly that the
   call is theirs. */
.contentagent-ui .ca-yours {
  margin: var(--ca-space-3) 0 0;
  padding-top: var(--ca-space-2);
  border-top: 1px solid var(--ca-border);
}

.contentagent-ui .ca-yours__title {
  margin: 0 0 var(--ca-space-1);
  font-size: 0.8125rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ca-text-meta);
}

.contentagent-ui .ca-yours__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--ca-space-1);
}

.contentagent-ui .ca-yours__item {
  font-size: 0.8125rem;
  color: var(--ca-text-body);
  line-height: var(--ca-leading-body);
}

.contentagent-ui .ca-yours__where {
  display: block;
  color: var(--ca-text-meta);
  font-size: 0.75rem;
}

/* The editor's verdict on the final review screen. Three short fields, no
   score: a number would be gamed in a week and would mean nothing across two
   articles. The judgement reads at body size because it is the one thing on
   the screen written for a person rather than extracted from a check. */

.contentagent-ui .ca-verdict {
  display: grid;
  gap: var(--ca-space-2);
}

.contentagent-ui .ca-verdict__judgement {
  margin: 0;
  font-size: 0.9375rem;
  line-height: var(--ca-leading-body);
  color: var(--ca-text-body);
}

.contentagent-ui .ca-verdict__item {
  margin: 0;
  padding-left: var(--ca-space-2);
  border-left: 2px solid var(--ca-border);
}

.contentagent-ui .ca-verdict__label {
  display: block;
  margin-bottom: 2px;
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ca-text-meta);
}

.contentagent-ui .ca-verdict__text {
  margin: 0;
  font-size: 0.875rem;
  line-height: var(--ca-leading-body);
  color: var(--ca-text-body);
}

/* Passages of our own published articles found surviving in a draft. The
   quote is set apart so a person can read the actual words rather than a
   count -- the decision is whether that sentence should be there, and a
   number cannot answer it. */

.contentagent-ui .ca-reuse {
  list-style: none;
  margin: 0 0 var(--ca-space-2);
  padding: 0;
  display: grid;
  gap: var(--ca-space-2);
}

.contentagent-ui .ca-reuse__item {
  padding-left: var(--ca-space-2);
  border-left: 2px solid var(--ca-border);
}

.contentagent-ui .ca-reuse__quote {
  margin: 0 0 2px;
  font-size: 0.8125rem;
  line-height: var(--ca-leading-body);
  color: var(--ca-text-body);
}

.contentagent-ui .ca-reuse__where {
  display: block;
  font-size: 0.75rem;
  color: var(--ca-text-meta);
  word-break: break-all;
}

/* The dashboard panel. Wagtail's own `.panel summary nice-padding` supplies
   the card; these rules only cover what is inside it.

   Kept deliberately small — it sits on a screen the rest of the team owns, and
   a panel that shouts there is a panel somebody turns off. */
.contentagent-ui.ca-dashpanel {
  display: grid;
  gap: var(--ca-space-2);
}

.contentagent-ui .ca-dashpanel__lead {
  margin: 0;
  max-width: var(--ca-measure);
  font-size: 0.9375rem;
  line-height: var(--ca-leading-body);
  color: var(--ca-text-body);
}

/* The count is the reason to look, so here it leads rather than annotates.
   The base `.ca-chip__count` is the muted form used on the empty search
   screen, where the label carries the meaning and the number is incidental. */
.contentagent-ui .ca-dashpanel .ca-chip {
  padding: 0.35rem 0.75rem;
}

.contentagent-ui .ca-dashpanel .ca-chip__count {
  font-size: 1rem;
  font-weight: 700;
  color: var(--ca-text);
}

.contentagent-ui .ca-dashpanel__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--ca-space-2);
  margin: 0;
}

/* A link that is available without competing with the button beside it. */
.contentagent-ui .ca-quiet {
  font-size: 0.8125rem;
  color: var(--ca-text-meta);
  text-decoration: underline;
  text-underline-offset: 0.15em;
}

.contentagent-ui .ca-quiet:hover,
.contentagent-ui .ca-quiet:focus-visible {
  color: var(--ca-text);
}

/* The dashboard panel's three waiting counts, as tiles.

   In contentagent.css rather than admin-theme.css because this panel renders
   whenever somebody can see the queue, regardless of the admin theme flag —
   styling it in the gated file would leave it bare when the flag is off. */
.contentagent-ui .ca-tiles {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--ca-space-2);
}

.contentagent-ui .ca-tile {
  display: grid;
  gap: 0.1rem;
  min-width: 7.5rem;
  padding: var(--ca-space-2) var(--ca-space-3);
  border: 1px solid var(--ca-border);
  border-radius: var(--ca-radius-sm);
  background: var(--ca-surface);
  text-decoration: none;
}

.contentagent-ui .ca-tile:hover,
.contentagent-ui .ca-tile:focus-visible {
  border-color: var(--ca-text-meta);
  text-decoration: none;
}

.contentagent-ui .ca-tile__count {
  font-size: 1.5rem;
  font-weight: 700;
  line-height: 1.1;
  color: var(--ca-text);
}

.contentagent-ui .ca-tile__label {
  font-size: 0.8125rem;
  color: var(--ca-text-meta);
}

/* ===========================================================================
 * Spacing fixes — measured on the running admin, not guessed.
 * =========================================================================== */

/* Every content agent screen sat flush against the page header: the header's
   bottom edge and the wrapper's top edge were both at page pixel 71, with
   margin-top and padding-top both 0. The title bar and the first line of
   content read as one crushed block, and the page actions looked like they
   had fallen out of the header.

   `.ca-page` rather than plain `.contentagent-ui`, because the dashboard
   panels carry that class too and would each gain 2rem of interior padding.
   A class of our own rather than a descendant selector off Wagtail's
   `.nice-padding`: the first attempt used the latter and silently missed the
   topic queue and the audit log, whose wrapper lives inside Wagtail's generic
   index template and is not a child of that gutter. One class, every screen,
   and no Wagtail class name to break on an upgrade. */
.contentagent-ui.ca-page {
  padding-top: var(--ca-space-4);
}

/* Table cells. The findings table on the review gate is where this matters:
   it is read by somebody deciding whether an article can be published, and
   the header row ran into the first finding.

   Wagtail's .listing already pads cells (7.7px/12.8px on th, 12.9px on td) —
   the reported "0px" was the gap between the two rows' boxes, which is 0 in
   any collapsed-border table because padding sits inside the cell. The real
   defect is that nothing separates the two rows, and that the th's bottom
   padding is smaller than the td's top padding, so the header sits low and
   reads as part of the first row. A rule under the header fixes what padding
   alone cannot. */
.contentagent-ui table.listing th,
.contentagent-ui table.ca-table th {
  padding: var(--ca-space-1) var(--ca-space-2);
}

.contentagent-ui table.listing td,
.contentagent-ui table.ca-table td {
  padding: var(--ca-space-2);
}

.contentagent-ui table.listing thead th,
.contentagent-ui table.ca-table thead th {
  border-bottom: 1px solid var(--ca-border);
}

/* A summed row inside a table — the two headline figures on the Spend screen
   and the gap between them. A rule above it rather than a background, so it
   reads as an arithmetic total and not as a selected row. */
.contentagent-ui table.ca-table tr.ca-row--total td {
  border-top: 1px solid var(--ca-border);
}

/* The findings table's columns, sized from what they actually hold.
   Measured across 123 editor findings: the pointer half of `location` has a
   median length of 31 characters, so "Where" needs a fraction of the 568px
   auto layout was giving it once the quotation is out of the cell. The space
   goes to the two columns somebody reads to decide. */
.contentagent-ui .ca-col-problem {
  min-width: 260px;
}

.contentagent-ui .ca-col-where {
  min-width: 120px;
  max-width: 200px;
}

.contentagent-ui .ca-col-fix {
  min-width: 220px;
}

/* The quotation, on its own row under the finding it belongs to. Full width,
   so it wraps as prose instead of being truncated into uselessness. */
.contentagent-ui tr.ca-quote > .ca-quote__cell {
  padding-top: 0;
  padding-bottom: var(--ca-space-2);
  border-bottom: 1px solid var(--ca-border);
}

.contentagent-ui .ca-row--quoted > td {
  border-bottom: 0;
}

.contentagent-ui .ca-quote__label {
  margin-inline-end: var(--ca-space-1);
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ca-text-meta);
}

.contentagent-ui .ca-quote__text {
  color: var(--ca-text-body);
  font-style: italic;
}

/* The standing-note form on the Patterns screen. */
.contentagent-ui .ca-noteform {
  display: grid;
  gap: var(--ca-space-2);
  max-width: 46rem;
  margin-top: var(--ca-space-2);
}

.contentagent-ui .ca-field__note {
  display: block;
  margin-top: 0.2rem;
  font-size: 0.8125rem;
  line-height: var(--ca-leading-body);
  color: var(--ca-text-meta);
}

/* A title that is a link has to look like one. The topic queue's titles were
   links from the start, drawn in body text with no underline, so a person
   clicking "a topic" saw nothing that said where to click. Quiet at rest,
   plainly a link on hover and focus. */
.contentagent-ui a.ca-row__title {
  text-decoration: underline;
  text-decoration-color: var(--ca-border);
  text-underline-offset: 3px;
}

.contentagent-ui a.ca-row__title:hover,
.contentagent-ui a.ca-row__title:focus-visible {
  color: var(--w-color-text-link-default);
  text-decoration-color: currentColor;
}

/* The run page's action row: Stop opens onto its own line, so the reason
   field gets the full width rather than the side column's. */
.contentagent-ui .ca-row--wrap {
  flex-wrap: wrap;
}

.contentagent-ui .ca-stop > summary {
  list-style: none;
  cursor: pointer;
}

.contentagent-ui .ca-stop > summary::-webkit-details-marker {
  display: none;
}

.contentagent-ui .ca-stop[open] {
  flex-basis: 100%;
}

.contentagent-ui .ca-stop__form {
  margin-top: var(--ca-space-2);
  padding: var(--ca-space-2);
  border: 1px solid var(--ca-flagged-br);
  border-radius: var(--ca-radius-sm);
  background: var(--ca-flagged-bg);
}

/* "Look up the keywords" sits above the keyword table, with its cost under it. */
.contentagent-ui .ca-lookup {
  margin: 0 0 var(--ca-space-3);
}

.contentagent-ui .ca-lookup .ca-meta {
  margin: 0.4rem 0 0;
}

/* Role buttons under the role pill on the topic page's keyword table. */
.contentagent-ui .ca-quick--roles {
  margin-top: 0.35rem;
  flex-wrap: wrap;
}

/* The topic queue has seven columns since the Type column arrived, and at
   1440px Score and Decide sat past the card's right edge. Two things were
   holding it wide: Decide kept Approve, Reject and the missing-keyword pill
   on one unbreakable line (498px), and the title truncated at 34rem. Decide
   now wraps onto a second line and the title truncates sooner. */
.contentagent-ui #listing-results td.ca-col-decide {
  white-space: normal;
}

.contentagent-ui #listing-results td.ca-col-decide .ca-quick {
  flex-wrap: wrap;
}

/* The title takes whatever the other columns leave, and truncates to fit it:
   width 100% with max-width 0 is what lets a table cell shrink below its
   text. A fixed truncation width could not, and was still 69px too wide. */
.contentagent-ui #listing-results td.ca-col-title {
  width: 100%;
  max-width: 0;
}

.contentagent-ui #listing-results td.ca-col-title .ca-truncate {
  max-width: 100%;
}

/* The topic page's keyword table ran past its card at 1440px (31px on topic
   97, whose "Hazard Communication Standard 2024 update" is 41 characters):
   the term truncated at 34rem, so its cell would not shrink and pushed Source
   off the edge. The queue's fix, on this table: the term takes what the other
   columns leave and truncates to it, with the full term in its tooltip. */
.contentagent-ui table.ca-table--keywords td.ca-col-title {
  width: 100%;
  max-width: 0;
}

.contentagent-ui table.ca-table--keywords td.ca-col-title .ca-truncate {
  max-width: 100%;
}

/* The queue's Keywords cell holds two terms since build 34. Uncapped, a long
   secondary took its width out of the title, which is the column people read.
   15rem until the gutter (build 38, below), 12rem since. */
.contentagent-ui #listing-results td.ca-col-keywords .ca-truncate {
  max-width: 12rem;
}

/* ===========================================================================
 * Build 38: one gutter, the proposed band, the approved list.
 * =========================================================================== */

/* ONE LEFT GUTTER. Not in this file: it is Wagtail's `.nice-padding`
 * (1.25rem, 5rem from 50em), which Wagtail's generic base puts around every
 * hand-written screen and which generic/index.html now puts around the two
 * listings as well. Measured at 1440 on 2026-09-24: thirteen screens had their
 * first line at x = 280, 80px from the sidebar, and the topic queue and audit
 * log at x = 200, touching it. A rule of our own here was tried first and
 * undone: outside `.nice-padding`, Wagtail pads every `.listing` table's first
 * cell with 5rem, so each table on every screen gained a second 80px gutter
 * inside the first. */

/* THE PROPOSED BAND: the first thing on the landing page, drawn as first.
 *
 * Every other band is a small uppercase caption over a panel. This one gets
 * a heading a size up, its count as a figure, and the amber edge that means
 * "waiting on a person" (the same edge the Wagtail dashboard's waiting panel
 * has). Rows carry their decision on the right. */
.contentagent-ui .ca-lead {
  margin: 0 0 var(--ca-space-4);
  padding: var(--ca-space-3) var(--ca-space-3) var(--ca-space-2);
  background-color: var(--ca-surface);
  border: 1px solid var(--ca-border);
  border-inline-start: 4px solid var(--ca-waiting-br);
  border-radius: var(--ca-radius);
  box-shadow: var(--ca-shadow-raised);
}

.contentagent-ui .ca-lead__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--ca-space-1) var(--ca-space-3);
  margin-bottom: var(--ca-space-1);
}

.contentagent-ui .ca-lead__title {
  display: flex;
  align-items: baseline;
  gap: var(--ca-space-2);
  margin: 0;
  font-family: var(--ca-font-display);
  font-size: 1.5rem;
  font-weight: 600;
  line-height: var(--ca-leading-heading);
  letter-spacing: -0.015em;
  color: var(--ca-text);
}

.contentagent-ui .ca-lead__count {
  font-size: 1.5rem;
  font-variant-numeric: tabular-nums;
  color: var(--ca-waiting-fg);
}

.contentagent-ui .ca-lead__note {
  margin: 0;
  max-width: var(--ca-measure);
  font-size: 0.875rem;
  color: var(--ca-text-meta);
}

.contentagent-ui .ca-lead__rows {
  margin: 0;
  padding: 0;
  list-style: none;
}

.contentagent-ui .ca-lead__row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--ca-space-3);
  padding: var(--ca-space-2) 0;
  border-bottom: 1px solid var(--ca-border);
}

.contentagent-ui .ca-lead__main {
  min-width: 0;
}

.contentagent-ui .ca-lead__topic {
  font-size: 1.0625rem;
  font-weight: 600;
  line-height: var(--ca-leading-heading);
  color: var(--ca-text);
  text-decoration: underline;
  text-decoration-color: var(--ca-border);
  text-underline-offset: 3px;
}

.contentagent-ui .ca-lead__topic:hover,
.contentagent-ui .ca-lead__topic:focus-visible {
  color: var(--w-color-text-link-default);
  text-decoration-color: currentColor;
}

.contentagent-ui .ca-lead__why,
.contentagent-ui .ca-lead__kw {
  max-width: var(--ca-measure);
  margin: 0.3rem 0 0;
  font-size: 0.875rem;
  line-height: var(--ca-leading-body);
  color: var(--ca-text-body);
}

.contentagent-ui .ca-lead__why .ca-pill {
  margin-inline-end: 0.35rem;
  font-size: 0.75rem;
  color: var(--ca-text-meta);
  border-color: var(--ca-border);
}

/* Two lines of why-now, the rest in the tooltip: five rows of it in full
   pushed the plans and drafts off a 900px screen. */
.contentagent-ui .ca-lead__why {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
}

.contentagent-ui .ca-lead__kw {
  color: var(--ca-text-meta);
}

.contentagent-ui .ca-lead__kw strong {
  color: var(--ca-text-body);
}

.contentagent-ui .ca-lead__side {
  display: flex;
  align-items: center;
  gap: var(--ca-space-2);
  flex-shrink: 0;
}

.contentagent-ui .ca-lead__score {
  font-family: var(--ca-font-display);
  font-size: 1.125rem;
  font-variant-numeric: tabular-nums;
  color: var(--ca-text);
}

.contentagent-ui .ca-lead__form {
  margin: 0;
}

.contentagent-ui .ca-lead__reject {
  font-size: 0.8125rem;
  color: var(--ca-text-meta);
}

.contentagent-ui .ca-lead__empty,
.contentagent-ui .ca-lead__foot {
  margin: var(--ca-space-2) 0 0;
  font-size: 0.875rem;
  color: var(--ca-text-meta);
}

/* Phone width: the decision drops under the topic instead of squeezing it. */
@media (max-width: 40rem) {
  .contentagent-ui .ca-lead__row {
    flex-direction: column;
    gap: var(--ca-space-1);
  }
}

/* The earlier-failures line under "Moving on its own". */
.contentagent-ui .ca-history {
  margin: var(--ca-space-2) 0 0;
}

/* THE QUEUE'S APPROVED LIST, with the calendar beside it. */
.contentagent-ui .ca-approved {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(14rem, 18rem);
  gap: var(--ca-space-4);
  align-items: start;
}

@media (max-width: 62rem) {
  .contentagent-ui .ca-approved {
    grid-template-columns: minmax(0, 1fr);
  }
}

.contentagent-ui .ca-dated {
  margin: 0;
  padding: 0;
  list-style: none;
}

.contentagent-ui .ca-dated__row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--ca-space-2) var(--ca-space-3);
  padding: var(--ca-space-2) 0;
  border-bottom: 1px solid var(--ca-border);
  /* "Give it a date" links to #approved-<pk>. Wagtail's slim header is
     sticky and 71px tall, so the row lands clear of it rather than under. */
  scroll-margin-top: calc(var(--ca-space-4) * 3);
}

.contentagent-ui .ca-dated__row:target {
  outline: 2px solid var(--ca-waiting-br);
  outline-offset: 4px;
  border-radius: var(--ca-radius-sm);
}

.contentagent-ui .ca-dated__main {
  flex: 1 1 18rem;
  min-width: 0;
}

.contentagent-ui .ca-dated__topic {
  font-weight: 600;
  line-height: var(--ca-leading-heading);
  color: var(--ca-text);
  text-decoration: underline;
  text-decoration-color: var(--ca-border);
  text-underline-offset: 3px;
}

.contentagent-ui .ca-dated__meta {
  margin: 0.3rem 0 0;
  font-size: 0.8125rem;
  color: var(--ca-text-meta);
}

.contentagent-ui .ca-dated__meta .ca-pill {
  margin-inline-end: 0.35rem;
  font-size: 0.75rem;
  border-color: var(--ca-border);
}

.contentagent-ui .ca-dated__acts {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--ca-space-1) var(--ca-space-2);
}

.contentagent-ui .ca-dated__form {
  display: flex;
  align-items: center;
  gap: var(--ca-space-1);
  margin: 0;
}

/* Wagtail draws a date field at form-page size (a 2.625rem min-height),
   which dwarfed the small buttons beside it on every row. min-height is the
   property to beat: a height alone measured 42px, unchanged. */
.contentagent-ui .ca-dated__form input[type="date"] {
  width: auto;
  height: 2.25em;
  min-height: 0;
  padding: 0 0.5rem;
  font-size: 0.875rem;
}

/* WHAT IS ALREADY BOOKED, beside every date field. */
.contentagent-ui .ca-ahead {
  padding: var(--ca-space-2) var(--ca-space-3);
  border: 1px solid var(--ca-border);
  border-radius: var(--ca-radius-sm);
  background-color: var(--ca-surface-head);
  font-size: 0.8125rem;
}

.contentagent-ui .ca-ahead__title {
  margin: 0 0 var(--ca-space-1);
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--ca-text-meta);
}

.contentagent-ui .ca-ahead__list {
  margin: 0 0 var(--ca-space-1);
  padding: 0;
  list-style: none;
}

.contentagent-ui .ca-ahead__list li {
  margin: 0 0 0.3rem;
  line-height: var(--ca-leading-heading);
}

.contentagent-ui .ca-ahead__date {
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--ca-text);
}

.contentagent-ui .ca-ahead__none {
  margin: 0 0 var(--ca-space-1);
  color: var(--ca-text-meta);
}

/* The topic page's approve card: the date on the left, the booked dates on
   the right. */
.contentagent-ui .ca-datepick {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(14rem, 18rem);
  gap: var(--ca-space-3);
  align-items: start;
  margin-bottom: var(--ca-space-2);
}

@media (max-width: 62rem) {
  .contentagent-ui .ca-datepick {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* THE QUEUE TABLE, INSIDE THE GUTTER. With 80px each side, the queue's table
   measured 1117px in a 1038px panel at 1440: the title column takes what the
   others leave (see above), so the others sat at their widest, with Approve
   and Reject on one line, a 15rem keyword, "not looked up" on one line and
   "Already covered?" unbroken. Each now gives some back (the keyword cap is
   the rule above, now 12rem); together they free more than the 79px. At 1280 it is 87px over and scrolls inside its panel,
   as it did before the gutter (79px). */
.contentagent-ui #listing-results td.ca-col-decide .ca-quick {
  max-width: 11rem;
}

/* Inside that 11rem, "needs PRIMARY + SECONDARY" wraps rather than running
   out of the cell. */
.contentagent-ui #listing-results td.ca-col-decide .ca-pill {
  white-space: normal;
}

.contentagent-ui #listing-results td.ca-col-num .ca-unmeasured {
  display: inline-block;
  max-width: 4.5rem;
  white-space: normal;
}

.contentagent-ui #listing-results th.ca-col-tag {
  white-space: normal;
}

/* ------------------------------------------------- images this piece needs */

/* The hero at its own pixel size, up to the card's width. Never upscaled:
   a person is judging lettering, and an enlarged image would soften exactly
   the detail they are looking for. At 1440 the card is about 1080px wide, so
   a 1344x768 hero shows at 80% and a 1024x1024 one at its own size. */
.contentagent-ui .ca-hero {
  margin: 0 0 var(--ca-space-3);
}

.contentagent-ui .ca-hero__link {
  display: inline-block;
  max-width: 100%;
}

.contentagent-ui .ca-hero__img {
  display: block;
  max-width: 100%;
  height: auto;
  border: 1px solid var(--ca-border);
  border-radius: var(--ca-radius-sm);
}

.contentagent-ui .ca-hero figcaption {
  max-width: var(--ca-measure);
  margin-top: var(--ca-space-1);
}

/* The finished video at the gate (build 57). Capped at 720px rather than shown
   at its own size like the hero: nobody is judging pixels here, they are
   watching it once to decide, and a 1920-wide player would push the decision
   buttons off the screen. 16:9 is HeyGen's output and the only shape this
   pipeline asks for, so the box reserves it and the frame never jumps when the
   poster loads. */
.contentagent-ui .ca-video {
  margin: 0 0 var(--ca-space-3);
}

.contentagent-ui .ca-video__player {
  display: block;
  width: 100%;
  max-width: 720px;
  aspect-ratio: 16 / 9;
  background: #000;
  border: 1px solid var(--ca-border);
  border-radius: var(--ca-radius-sm);
}

.contentagent-ui .ca-video figcaption {
  max-width: var(--ca-measure);
  margin-top: var(--ca-space-1);
}

.contentagent-ui .ca-send {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--ca-space-1) var(--ca-space-2);
  margin: var(--ca-space-2) 0 var(--ca-space-3);
}

.contentagent-ui .ca-send__preview {
  flex-basis: 100%;
}

.contentagent-ui .ca-send__preview > summary {
  cursor: pointer;
}

.contentagent-ui .ca-concepts {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--ca-space-3);
}

.contentagent-ui .ca-concept {
  padding-top: var(--ca-space-3);
  border-top: 1px solid var(--ca-border);
  scroll-margin-top: calc(var(--ca-space-4) * 3);
}

.contentagent-ui .ca-concept__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--ca-space-1);
  margin-bottom: var(--ca-space-2);
}

.contentagent-ui .ca-concept__num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.75rem;
  height: 1.75rem;
  border-radius: 999px;
  background: var(--ca-surface-head);
  color: var(--ca-text);
  font-weight: 600;
  font-size: 0.875rem;
}

.contentagent-ui .ca-concept__title {
  margin: 0;
  font-size: 1rem;
  line-height: var(--ca-leading-heading);
  color: var(--ca-text);
}

/* The fields, with the file the designer sent beside them once there is one. */
.contentagent-ui .ca-concept__body {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--ca-space-3);
}

.contentagent-ui .ca-concept__body:has(.ca-concept__thumb) {
  grid-template-columns: minmax(0, 1fr) 18rem;
}

.contentagent-ui .ca-concept__fields th {
  width: 10rem;
}

.contentagent-ui .ca-concept__fields td {
  max-width: var(--ca-measure);
}

.contentagent-ui .ca-concept__fields code {
  word-break: break-all;
}

.contentagent-ui .ca-concept__thumb img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--ca-border);
  border-radius: var(--ca-radius-sm);
}

.contentagent-ui .ca-concept__upload {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--ca-space-1) var(--ca-space-2);
  margin-top: var(--ca-space-2);
}

.contentagent-ui .ca-concept__upload .ca-field {
  margin-bottom: 0;
}

.contentagent-ui .ca-concept__upload select {
  max-width: 32rem;
}

@media (max-width: 800px) {
  .contentagent-ui .ca-concept__body:has(.ca-concept__thumb) {
    grid-template-columns: minmax(0, 1fr);
  }

  .contentagent-ui .ca-concept__fields th {
    width: 7rem;
  }
}

/* ------------------------------------------------------- before you start */

/* The New piece status list: one row per fact a person needs at the moment
   they press Start, label / state / way to change it. Built for more than one
   row: a later build adds whether a worker is listening, as a second row. */
.contentagent-ui .ca-status {
  margin: 0 0 var(--ca-space-3);
  padding: 0;
  border: 1px solid var(--ca-border);
  border-radius: var(--ca-radius);
  background: var(--ca-surface);
}

.contentagent-ui .ca-status__row {
  display: grid;
  grid-template-columns: 10rem minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--ca-space-1) var(--ca-space-3);
  padding: var(--ca-space-2) var(--ca-space-3);
}

.contentagent-ui .ca-status__row + .ca-status__row {
  border-top: 1px solid var(--ca-border);
}

.contentagent-ui .ca-status__label {
  margin: 0;
  font-weight: 600;
  color: var(--ca-text);
}

.contentagent-ui .ca-status__state,
.contentagent-ui .ca-status__action {
  margin: 0;
}

.contentagent-ui .ca-status__state .ca-sub {
  display: block;
  margin-top: 2px;
}

.contentagent-ui .ca-status[data-on="1"] .ca-status__when-off,
.contentagent-ui .ca-status[data-on="0"] .ca-status__when-on {
  display: none;
}

@media (max-width: 800px) {
  .contentagent-ui .ca-status__row {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* -------------------------------------------------- discovery refusals
 *
 * Build 42, Part 1: what the last discovery run refused, under the topic
 * queue's provenance line. The provenance line's register (ca-meta), with no
 * pill and no warning colour: a refusal is the duplicate check working.
 * Its own block after that paragraph, so the drift sentence at the
 * paragraph's end stays the last thing in it. */

.contentagent-ui .ca-refusals {
  max-width: var(--ca-measure);
  margin: 0 0 var(--ca-space-3);
}

.contentagent-ui .ca-refusals .ca-refusals__lead,
.contentagent-ui .ca-refusals .ca-refusals__run {
  margin-bottom: var(--ca-space-1);
}

.contentagent-ui .ca-refusals__list {
  margin: 0 0 var(--ca-space-2);
  padding-left: 1.25rem;
  font-size: 0.875rem;
  line-height: var(--ca-leading-body);
  color: var(--ca-text-meta);
}

.contentagent-ui .ca-refusals__item + .ca-refusals__item {
  margin-top: 0.25rem;
}

.contentagent-ui .ca-refusals__item a {
  overflow-wrap: anywhere;
}

.contentagent-ui .ca-refusals__title {
  color: var(--ca-text);
}

/* Wagtail's reset hides the summary marker; without it nothing says the
 * line opens. The browser's own disclosure triangle, put back. */
.contentagent-ui .ca-refusals__earlier > summary {
  display: list-item;
  list-style: disclosure-closed inside;
  cursor: pointer;
  margin-bottom: var(--ca-space-1);
}

.contentagent-ui .ca-refusals__earlier[open] > summary {
  list-style-type: disclosure-open;
}

/* ---------------------------------------------------------------------------
 * One press, and what it is doing (build 44).
 *
 * `.ca-start-status` is the line partials/_start_once.html puts under a Start
 * form once it is pressed: what the system is doing while the button is
 * disabled, including "a worker is being started" when it is. A whole line of
 * its own, including inside the queue's wrapping action rows.
 *
 * `.ca-notsent` is a decision whose task could not be queued, on the two
 * gates; the run page tints its own action row the same way. Waiting tones,
 * not flagged: nothing failed that a person did, and the way out is beside
 * the sentence. Colours reuse the --ca-waiting-* tokens, already defined for
 * the dark themes.
 * ------------------------------------------------------------------------ */
.contentagent-ui .ca-start-status {
  flex-basis: 100%;
  max-width: var(--ca-measure);
  margin: var(--ca-space-1) 0 0;
  font-size: 0.875rem;
  line-height: var(--ca-leading-body);
  color: var(--ca-text-body);
}

.contentagent-ui .ca-notsent {
  margin-bottom: var(--ca-space-4);
  padding: var(--ca-space-3);
  border: 1px solid var(--ca-waiting-br);
  border-left-width: 4px;
  border-radius: var(--ca-radius);
  background: var(--ca-waiting-bg);
}

.contentagent-ui .ca-notsent__title {
  margin: 0 0 var(--ca-space-1);
  font-size: 1.05rem;
  color: var(--ca-waiting-fg);
}

.contentagent-ui .ca-notsent__text {
  max-width: var(--ca-measure);
  margin: 0;
  color: var(--ca-text-body);
}

.contentagent-ui .ca-row--notsent {
  margin-bottom: var(--ca-space-3);
  padding: 0.85rem var(--ca-space-3);
  border: 1px solid var(--ca-waiting-br);
  border-left-width: 4px;
  border-radius: var(--ca-radius);
  background: var(--ca-waiting-bg);
}

.contentagent-ui .ca-send-again {
  margin: var(--ca-space-2) 0 0;
}

/* A failed run's box on its page (build 48): what it kept, and carrying it on. */
.contentagent-ui .ca-row--failed {
  margin-bottom: var(--ca-space-3);
  padding: 0.85rem var(--ca-space-3);
  border: 1px solid var(--ca-flagged-br);
  border-left-width: 4px;
  border-radius: var(--ca-radius);
  background: var(--ca-flagged-bg);
}

.contentagent-ui .ca-kept {
  margin: var(--ca-space-2) 0 0;
}

.contentagent-ui .ca-carry-on {
  margin: var(--ca-space-2) 0 0;
}

/* Build 49. The outline gate's line on the headings against the word target,
   under "Planned length", and the queue's list of Scout replies that did not
   parse, under its provenance line. Both in the ca-meta register. */
.contentagent-ui .ca-section-fit {
    margin-top: 0.25rem;
}

.contentagent-ui .ca-discovery-replies ul {
    margin: 0.25rem 0 0.75rem 1.25rem;
    padding: 0;
}

/* ------------------------------------------------- build 52: the 36 items */

/* The regression band. Full width, above every card, and loud: an item that
   passed on the previous run and fails on this one is the one thing on the
   final gate nobody may scroll past. Colour is not the only signal — the
   count and the sentence say it too. */
.contentagent-ui .ca-regress {
  margin: 0 0 var(--ca-space-3);
  padding: var(--ca-space-3);
  border: 2px solid var(--ca-flagged-br);
  border-left-width: 6px;
  border-radius: var(--ca-radius-sm);
  background-color: var(--ca-flagged-bg);
}

.contentagent-ui .ca-regress__lead {
  margin: 0;
  font-size: 1rem;
  font-weight: 600;
  color: var(--ca-flagged-fg);
}

.contentagent-ui .ca-regress__count {
  font-size: 1.5rem;
  font-weight: 700;
  line-height: 1;
  vertical-align: -0.1em;
}

.contentagent-ui .ca-regress__list {
  list-style: none;
  margin: var(--ca-space-2) 0 0;
  padding: 0;
  display: grid;
  gap: var(--ca-space-2);
}

.contentagent-ui .ca-regress__item {
  display: grid;
  gap: 0.15rem;
}

.contentagent-ui .ca-regress__what {
  font-weight: 600;
  font-size: 0.9375rem;
  color: var(--ca-text);
}

.contentagent-ui .ca-regress__measured,
.contentagent-ui .ca-regress__where {
  font-size: 0.8125rem;
  color: var(--ca-text-meta);
  line-height: var(--ca-leading-body);
}

.contentagent-ui .ca-regress__foot {
  margin: var(--ca-space-2) 0 0;
  font-size: 0.8125rem;
  color: var(--ca-text-meta);
}

/* Build 71. The publish-ready items that refuse the approval. Same band as
   a regression and named apart on purpose: a regression is a comparison and
   this is a refusal, and a test asserts a screen with no regression carries
   no ca-regress__lead. */
.contentagent-ui .ca-gateblock {
  margin: 0 0 var(--ca-space-3);
  padding: var(--ca-space-3);
  border: 2px solid var(--ca-flagged-br);
  border-left-width: 6px;
  border-radius: var(--ca-radius-sm);
  background-color: var(--ca-flagged-bg);
}

.contentagent-ui .ca-gateblock__lead {
  margin: 0;
  font-size: 1rem;
  font-weight: 600;
  color: var(--ca-flagged-fg);
}

.contentagent-ui .ca-gateblock__count {
  font-size: 1.5rem;
  font-weight: 700;
  line-height: 1;
  vertical-align: -0.1em;
}

.contentagent-ui .ca-gateblock__list {
  list-style: none;
  margin: var(--ca-space-2) 0 0;
  padding: 0;
  display: grid;
  gap: var(--ca-space-2);
}

.contentagent-ui .ca-gateblock__item {
  display: grid;
  gap: 0.15rem;
}

.contentagent-ui .ca-gateblock__what {
  font-weight: 600;
  font-size: 0.9375rem;
  color: var(--ca-text);
}

.contentagent-ui .ca-gateblock__measured,
.contentagent-ui .ca-gateblock__where {
  font-size: 0.8125rem;
  color: var(--ca-text-meta);
  line-height: var(--ca-leading-body);
}

.contentagent-ui .ca-gateblock__foot {
  margin: var(--ca-space-2) 0 0;
  font-size: 0.8125rem;
  color: var(--ca-text-meta);
}

/* Build 80, D1. The item-18 repair, inside the blocking band. It sits in the
   band rather than beside it because the point is that the piece is still
   blocked: the fix and the refusal are one thing, not a way around it. */
.contentagent-ui .ca-gateblock__repair {
  margin: var(--ca-space-2) 0 0;
  padding: var(--ca-space-2);
  background: var(--ca-surface);
  border: 1px solid var(--ca-border);
  border-radius: var(--ca-radius-sm);
}

.contentagent-ui .ca-gateblock__repairlabel {
  display: block;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--ca-text);
  margin-bottom: var(--ca-space-1);
}

.contentagent-ui .ca-gateblock__repairfield {
  width: 100%;
  box-sizing: border-box;
  font-size: 0.8125rem;
  line-height: var(--ca-leading-body);
}

.contentagent-ui .ca-gateblock__repairfoot {
  margin: var(--ca-space-1) 0 0;
  font-size: 0.8125rem;
  color: var(--ca-text-meta);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--ca-space-1);
}

.contentagent-ui .ca-gateblock__count-live {
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  color: var(--ca-text);
}

/* Outside 140-160. Carries a weight change as well as a colour, so it is not
   colour alone that says the number is wrong. */
.contentagent-ui .ca-gateblock__count-live.is-outside {
  color: var(--w-color-critical-100, #cd4444);
  text-decoration: underline;
}

/* The score card's three counters. "Needs a read" is neither green nor red on
   purpose: it is "nobody has looked at this", which is not a result. */
.contentagent-ui .ca-score {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--ca-space-1);
}

.contentagent-ui .ca-score__tile {
  display: grid;
  gap: 0.1rem;
  padding: var(--ca-space-2);
  border: 1px solid var(--ca-border);
  border-radius: var(--ca-radius-sm);
  text-align: center;
}

.contentagent-ui .ca-score__tile--pass {
  color: var(--ca-done-fg);
  border-color: var(--ca-done-br);
  background-color: var(--ca-done-bg);
}

.contentagent-ui .ca-score__tile--fail {
  color: var(--ca-flagged-fg);
  border-color: var(--ca-flagged-br);
  background-color: var(--ca-flagged-bg);
}

.contentagent-ui .ca-score__tile--read {
  color: var(--ca-waiting-fg);
  border-color: var(--ca-waiting-br);
  background-color: var(--ca-waiting-bg);
}

.contentagent-ui .ca-score__tile--na {
  color: var(--ca-text-meta);
  border-color: var(--ca-border);
  background-color: transparent;
}

.contentagent-ui .ca-score__figure {
  font-size: 1.5rem;
  font-weight: 700;
  line-height: 1.1;
}

.contentagent-ui .ca-score__label {
  font-size: 0.75rem;
  font-weight: 600;
  line-height: 1.2;
}

.contentagent-ui .ca-score__repairs {
  margin: var(--ca-space-2) 0 0;
  font-size: 0.8125rem;
  color: var(--ca-text-meta);
}

.contentagent-ui .ca-score__all {
  margin: var(--ca-space-2) 0 0;
  font-size: 0.8125rem;
}

.contentagent-ui .ca-score__all > summary {
  cursor: pointer;
  font-weight: 600;
  color: var(--ca-text);
}

.contentagent-ui .ca-score__group {
  margin: var(--ca-space-3) 0 var(--ca-space-1);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ca-text-meta);
}

.contentagent-ui .ca-score__items {
  margin: 0;
}

.contentagent-ui .ca-score__item--read .ca-check__mark {
  color: var(--ca-waiting-fg);
}

.contentagent-ui .ca-score__item--na .ca-check__mark {
  color: var(--ca-text-meta);
}

.contentagent-ui .ca-score__item--na .ca-check__label {
  color: var(--ca-text-meta);
}

.contentagent-ui .ca-score__item--pass .ca-check__mark {
  color: var(--ca-done-fg);
}

.contentagent-ui .ca-score__item--fail .ca-check__mark {
  color: var(--ca-flagged-fg);
}

.contentagent-ui .ca-score__item .ca-pill {
  margin-left: 0.35rem;
  font-size: 0.6875rem;
}

/* How to answer an item nobody can measure (build 60). `.ca-check` is a
   two-column grid and every child of it needs `grid-column: 2` or it lands in
   the 1.25rem mark column and wraps one word per line. */
.contentagent-ui .ca-score__how {
  grid-column: 2;
  margin-top: 0.4rem;
  padding: 0.5rem 0.6rem;
  border-left: 2px solid var(--w-color-border-furniture);
  background: var(--ca-sb-hover, rgba(127, 127, 127, 0.06));
  border-radius: var(--ca-sb-radius, 4px);
}

.contentagent-ui .ca-score__how > .ca-row__need {
  margin: 0 0 0.35rem;
  font-size: 0.8125rem;
}

.contentagent-ui .ca-score__how .ca-score__evidence {
  margin-top: 0;
}

.contentagent-ui .ca-score__evidence {
  grid-column: 2;
  margin: 0.35rem 0 0;
  padding-left: var(--ca-space-3);
  font-size: 0.75rem;
  color: var(--ca-text-meta);
  line-height: var(--ca-leading-body);
}

.contentagent-ui .ca-score__reads {
  grid-column: 2;
  margin-top: 0.2rem;
  font-size: 0.6875rem;
  font-style: italic;
  color: var(--ca-text-meta);
}

/* Build 62, Part 3 — picking several runs to archive from Needs you.
   The checkbox sits on its own line above the title with the run number
   beside it, so the row still reads title-first and the number a person
   needs in order to check what they ticked is on the screen rather than
   only in the link. */
.contentagent-ui .ca-bulk__pick {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin-bottom: 0.2rem;
  cursor: pointer;
}

.contentagent-ui .ca-bulk__pick input {
  margin: 0;
}

/* The archive control, under both run cards, inside the form that owns their
   checkboxes. Its sentence says what the next screen will do, because a
   person reads the button before they read anything else. */
.contentagent-ui .ca-bulk__bar {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin: 0 0 var(--ca-space-4);
  padding: var(--ca-space-2);
  border: 1px solid var(--ca-border);
  border-radius: var(--ca-radius-sm);
}

.contentagent-ui .ca-bulk__bar .ca-sub {
  max-width: var(--ca-measure);
}

/* The archive confirm screen's two buttons, across rather than stacked.
   `.ca-actions` is a column by default, which drew "Yes, archive 20 runs" as a
   full-width banner and Cancel as a second one under it — loud for a
   destructive press and impossible to read as "this one or that one". */
.contentagent-ui .ca-actions--confirm {
  flex-direction: row;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.6rem;
}

/* ---------------------------------------------------------------------------
 * "Out of date — not proposed" (build 68).
 *
 * The topic queue's third list, below the decide-list: proposed topics whose
 * stated reason has already happened. Collapsed, because on a healthy queue it
 * is empty or nearly so and a person opening the queue is there to decide on
 * the list above it. The rows reuse `.ca-dated`, so a topic looks the same
 * here as in the approved list.
 *
 * Wagtail's reset hides the summary marker; without it nothing says the line
 * opens. Same treatment as `.ca-refusals__earlier`.
 */
.contentagent-ui .ca-stale {
  margin-top: var(--ca-space-4);
}

.contentagent-ui .ca-stale > summary {
  display: list-item;
  list-style: disclosure-closed inside;
  cursor: pointer;
  font-weight: 600;
  color: var(--ca-text);
  margin-bottom: var(--ca-space-1);
}

.contentagent-ui .ca-stale[open] > summary {
  list-style-type: disclosure-open;
}


/* Build 73. The declared shape and its contract, at the outline gate. A piece
   that does not do the job its title announces is caught here, where an
   outline is free, rather than after a draft. */
.contentagent-ui .ca-shape {
    border: 1px solid var(--w-color-border-furniture, #cfd3d6);
    border-left: 4px solid var(--w-color-info-100, #0b6cab);
    border-radius: 4px;
    padding: var(--ca-space-2) var(--ca-space-3);
    margin: 0 0 var(--ca-space-3);
    background: var(--w-color-surface-page, #fff);
}
.contentagent-ui .ca-shape--missed { border-left-color: var(--w-color-critical-100, #cd4444); }
.contentagent-ui .ca-shape--asked { border-left-color: var(--w-color-warning-100, #faa500); }
/* Build 72. The ranking pages' shape: information, not a verdict. */
.contentagent-ui .ca-shape--bar { border-left-color: var(--w-color-info-100, #0073aa); }
.contentagent-ui .ca-shape__title { margin: 0 0 0.3rem; font-size: 1rem; }
.contentagent-ui .ca-shape__lead { margin: 0 0 0.6rem; font-size: 0.85rem; opacity: 0.85; }
.contentagent-ui .ca-shape__list { list-style: none; margin: 0; padding: 0; }
.contentagent-ui .ca-shape__item {
    display: grid;
    grid-template-columns: 1.4rem 1fr;
    gap: 0 0.4rem;
    padding: 0.35rem 0;
    border-top: 1px solid var(--w-color-border-furniture, #eee);
}
.contentagent-ui .ca-shape__mark { font-weight: 700; }
.contentagent-ui .ca-shape__item--ok .ca-shape__mark { color: var(--w-color-positive-100, #1b7f5a); }
.contentagent-ui .ca-shape__item--miss .ca-shape__mark { color: var(--w-color-critical-100, #cd4444); }
.contentagent-ui .ca-shape__item--warn .ca-shape__mark { color: var(--w-color-warning-100, #faa500); }
.contentagent-ui .ca-shape__item--note { opacity: 0.7; }
.contentagent-ui .ca-shape__must { font-weight: 600; }
.contentagent-ui .ca-shape__measured { grid-column: 2; font-size: 0.82rem; opacity: 0.85; }


/* Build 80, D3. The duplicate warning on New piece. A warning, not a
   refusal: it sits above the submit row rather than replacing it, and the
   button underneath still says "Create the piece". */
.contentagent-ui .ca-newpiece__dupe {
  margin: var(--ca-space-2) 0;
  padding: var(--ca-space-2);
  border: 1px solid var(--w-color-critical-100, #cd4444);
  border-radius: var(--ca-radius-sm);
  background: var(--ca-surface);
}

.contentagent-ui .ca-newpiece__dupelead {
  margin: 0;
  font-size: 0.875rem;
  color: var(--ca-text);
}

.contentagent-ui .ca-newpiece__dupelink {
  margin: var(--ca-space-1) 0;
  font-size: 0.8125rem;
  word-break: break-all;
}

/* Build 83, C56. The region's detected reason sits under the select; a region
 * with almost no authoritative domains of its own says so in the flagged
 * colour already used for a count that needs a look. No new tone. */
.contentagent-ui .ca-sub--warn {
  color: var(--ca-flagged-fg, #b3372c);
}

/* ------------------------------------------------------------------ */
/* The run feed. Build 86.                                             */
/*                                                                     */
/* Under the stage bar, never in place of it. A recovered failure is   */
/* the agent working, so it reads as an ordinary line; only the rows   */
/* that stop something carry a colour.                                 */
/* ------------------------------------------------------------------ */
.contentagent-ui .ca-feed {
  margin: var(--ca-space-2) 0 0;
  padding: 0;
  list-style: none;
  max-height: 22rem;
  overflow-y: auto;
  border-top: 1px solid var(--ca-border);
}

.contentagent-ui .ca-feed__line {
  padding: 0.3rem 0 0.3rem 0.95rem;
  font-size: 0.8125rem;
  line-height: 1.45;
  color: var(--ca-text-body);
  border-bottom: 1px solid var(--ca-border);
  position: relative;
  overflow-wrap: anywhere;
}

.contentagent-ui .ca-feed__line::before {
  content: "✓";
  position: absolute;
  left: 0;
  color: var(--ca-done-fg);
}

.contentagent-ui .ca-feed__line--problem {
  color: var(--ca-flagged-fg);
}

.contentagent-ui .ca-feed__line--problem::before {
  content: "!";
  color: var(--ca-flagged-fg);
}

.contentagent-ui .ca-feed__line--empty {
  color: var(--ca-text-meta);
}

.contentagent-ui .ca-feed__line--empty::before {
  content: "·";
  color: var(--ca-text-meta);
}

/* ------------------------------------------------------------------ */
/* Learned rules. Build 87.                                            */
/* A fact and a style rule are different kinds and are shown apart;    */
/* a proposal is not in force and is marked so.                        */
/* ------------------------------------------------------------------ */
.contentagent-ui .ca-lessons {
  margin: var(--ca-space-1) 0 0;
  padding: 0;
  list-style: none;
}

.contentagent-ui .ca-lesson {
  display: flex;
  align-items: baseline;
  gap: var(--ca-space-1);
  padding: var(--ca-space-1) 0;
  border-bottom: 1px solid var(--ca-border);
  font-size: 0.875rem;
}

.contentagent-ui .ca-lesson__text {
  flex: 1 1 auto;
  min-width: 0;
  color: var(--ca-text-body);
  overflow-wrap: anywhere;
}

.contentagent-ui .ca-lesson__meta {
  flex: 0 0 auto;
  font-size: 0.75rem;
  color: var(--ca-text-meta);
}

.contentagent-ui .ca-lesson__act {
  flex: 0 0 auto;
  margin: 0;
}

.contentagent-ui .ca-lesson--proposal .ca-lesson__meta {
  color: var(--ca-waiting-fg);
}
