/* ==========================================================================
   ClariPay — project extensions to BCDF
   --------------------------------------------------------------------------
   Not a shim layer (that is claripay.compat.css, which shrinks and dies). This
   is the small set of things SFMS needs that BCDF v1.0 does not ship yet:

     · a tablet/phone drawer for the MIS sidebar — BCDF simply hides it below
       1024px, which is fine for a desktop-first MIS but leaves a district
       official on a tablet with no navigation at all
     · a toast host position
     · the filterable-select wrapper that replaced Select2
     · the co-brand lockup for provincial white-labelling

   Everything here is a candidate to be upstreamed into BCDF. No hex — tokens
   only, so a province override still reaches it.
   ========================================================================== */


/* ── MIS sidebar drawer (≤1023px) ─────────────────────────────────────────
   Below the BCDF MIS breakpoint the sidebar becomes an off-canvas drawer
   opened from the topbar. Desktop is untouched. */
@media (max-width: 1023px) {
  /* Enterprise shell: the sidebar column collapses and the aside becomes the same drawer. */
  .bce-shell, .bce-shell.is-collapsed { grid-template-columns: minmax(0, 1fr); }
  .bce-side {
    position: fixed; top: 0; left: 0; bottom: 0; width: var(--bc-sidebar-w, 248px);
    height: 100vh; transform: translateX(-100%); transition: transform 220ms ease;
    z-index: var(--bc-z-drawer);
  }
  body.bc-nav-open .bce-side { transform: translateX(0); }
  .bc-mis__aside {
    display: flex !important;
    position: fixed;
    inset: 0 auto 0 0;
    width: var(--bc-sidebar-w);
    z-index: var(--bc-z-drawer);
    transform: translateX(-100%);
    transition: transform var(--bc-transition);
    box-shadow: var(--bc-sh-xl);
  }
  body.bc-nav-open .bc-mis__aside { transform: translateX(0); }
  body.bc-nav-open::after {
    content: "";
    position: fixed; inset: 0;
    z-index: calc(var(--bc-z-drawer) - 1);
    background: rgba(9, 25, 39, .45);
  }
  .cp-navtoggle { display: inline-flex !important; }
}
.cp-navtoggle { display: none; }


/* ── Topbar additions ─────────────────────────────────────────────────────
   The province strip: which province's books the user is currently in. On a
   national deployment this is the single most important piece of context on
   the screen, so it sits in the chrome, not in the page body. */
.cp-province {
  display: inline-flex;
  align-items: center;
  gap: var(--bc-s-2);
  padding: var(--bc-s-1) var(--bc-s-3);
  border: 1px solid var(--bc-border);
  border-radius: var(--bc-r-pill);
  font-size: var(--bc-fs-xs);
  font-weight: var(--bc-fw-semi);
  color: var(--bc-text-body);
  background: var(--bc-bg-surface);
  white-space: nowrap;
}
.cp-province__swatch {
  width: 10px; height: 10px;
  border-radius: 50%;
  background: var(--bc-accent-500);
  flex: 0 0 auto;
}
.cp-province img { height: 18px; width: auto; }

/* When the province is a choice rather than a label, the chip becomes the
   control instead of growing a second one beside it — same footprint, same
   place, so the answer to "whose books" never moves. */
.cp-province--pick { padding-right: var(--bc-s-2); }
.cp-province__select {
  border: 0;
  background: transparent;
  color: inherit;
  font: inherit;
  max-width: 200px;
  padding: 2px var(--bc-s-1);
  border-radius: var(--bc-r-xs);
  cursor: pointer;
}
.cp-province__select:focus-visible { outline: 2px solid var(--bc-accent-500); outline-offset: 1px; }
@media (max-width: 900px) { .cp-province { display: none; } }


/* ── Account menu ─────────────────────────────────────────────────────────
   One labelled menu in the top-right corner, in place of the unlabelled moon
   and rows buttons that used to sit there. Appearance and density are choices
   about the screen, so they belong with the person making them rather than
   loose in the chrome; sign out belongs here because that is where everyone
   looks for it first. */
.cp-user { position: relative; }
.cp-user__btn {
  display: inline-flex; align-items: center; gap: var(--bc-s-1);
  min-height: 34px; padding: 2px var(--bc-s-1) 2px 2px;
  border: 1px solid transparent; border-radius: var(--bc-r-pill);
  background: transparent; cursor: pointer; color: var(--bc-text-muted);
}
.cp-user__btn:hover { background: var(--bc-bg-sunken); border-color: var(--bc-border); }
.cp-user__btn:focus-visible { outline: 2px solid var(--bc-accent-500); outline-offset: 1px; }
.cp-user__caret { width: 14px; height: 14px; }

.cp-user__menu {
  /* Anchored right in its own right, not only via .dropdown-menu-end: this menu
     always hangs off the last control in the top bar, so opening leftward is a
     property of the component rather than something each caller must remember. */
  left: auto; right: 0;
  min-width: 260px; padding: 0;
  border: 1px solid var(--bc-border); border-radius: var(--bc-r-card);
  background: var(--bc-bg-surface); box-shadow: var(--bc-sh-lg);
  overflow: hidden;
}
.cp-user__head { padding: var(--bc-s-4); }
.cp-user__name  { font-weight: var(--bc-fw-semi); color: var(--bc-text-strong); text-transform: capitalize; }
.cp-user__email { font-size: var(--bc-fs-xs); color: var(--bc-text-muted); overflow-wrap: anywhere; }
.cp-user__meta  { display: flex; flex-wrap: wrap; align-items: center; gap: var(--bc-s-2);
                  margin-top: var(--bc-s-3); font-size: var(--bc-fs-xs); }
.cp-user__sep   { height: 1px; background: var(--bc-border); }

.cp-user__item {
  display: flex; align-items: center; gap: var(--bc-s-3);
  width: 100%; min-height: 40px; padding: 0 var(--bc-s-4);
  border: 0; background: transparent; cursor: pointer;
  font: inherit; font-size: var(--bc-fs-base); color: var(--bc-text-body); text-align: left;
}
.cp-user__item:hover { background: var(--bc-bg-sunken); color: var(--bc-text-strong); }
.cp-user__item:focus-visible { outline: 2px solid var(--bc-accent-500); outline-offset: -2px; }
.cp-user__item .bc-i { width: 16px; height: 16px; color: var(--bc-text-muted); flex: 0 0 auto; }
.cp-user__item--danger { color: var(--bc-danger-fg); }
.cp-user__item--danger:hover { background: var(--bc-danger-bg); color: var(--bc-danger-fg); }
.cp-user__item--danger .bc-i { color: currentColor; }
.cp-user__menu form { margin: 0; }


/* ── The primary button always has a readable label ───────────────────────
   This has broken twice, so it is guaranteed here rather than computed.

   _ProvinceTheme emits `.btn-primary { color: var(--cp-ink-on-accent) !important }`
   with the ink derived from the province's accent. Any failure in that chain —
   an unparseable colour, an undefined token, a stale compiled partial — lands
   as a label painted close to the button behind it. Measured, the live failure
   was Ink Navy on Civic Teal at 2.46:1: laid out, present in the DOM, and
   unreadable. Computing the safe value is not worth the risk of computing it
   wrong.

   Specificity beats source order between two !important declarations, so
   `html .btn.btn-primary` (0,2,1) wins over the partial's `.btn-primary`
   (0,1,0) even though the partial loads later. It therefore holds after a
   plain hard refresh, with no rebuild.

   Trade-off, stated plainly: a province with a PALE accent would get white on
   pale here. None in play has one — ClariPay teal and the KZN palette are both
   dark — and HexColourHelper.InkOn still exists for surfaces where contrast
   genuinely varies. If a pale-accent province is onboarded, revisit this rule. */
html .btn.btn-primary,
html .bc-btn.bc-btn--primary,
html .btn.btn-success,
html .btn.btn-danger,
html .btn.btn-dark,
html .btn.btn-navy { color: #FFFFFF !important; }

/* Icons inside those buttons follow the label, not the body ink. */
html .btn.btn-primary :is(i, svg),
html .bc-btn.bc-btn--primary :is(i, svg) { color: currentColor; }


/* The school strip: which school's books, alongside which province's. It is a
   real control rather than a label because a provincial or system user changes
   school constantly and every school screen reads this one answer. A school
   user gets the same shape with no select — their school is context, not a
   choice, and a one-option dropdown only invites a pointless click. */
.cp-school {
  display: inline-flex;
  align-items: center;
  gap: var(--bc-s-2);
  padding: var(--bc-s-1) var(--bc-s-2) var(--bc-s-1) var(--bc-s-3);
  border: 1px solid var(--bc-border);
  border-radius: var(--bc-r-pill);
  background: var(--bc-bg-surface);
  color: var(--bc-text-body);
  font-size: var(--bc-fs-xs);
  font-weight: var(--bc-fw-semi);
  white-space: nowrap;
  max-width: 280px;
}
.cp-school .bc-i { width: 14px; height: 14px; color: var(--bc-text-muted); flex: 0 0 auto; }
.cp-school--fixed { padding-right: var(--bc-s-3); }
.cp-school__name {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cp-school__select {
  border: 0;
  background: transparent;
  color: inherit;
  font: inherit;
  max-width: 220px;
  padding: 2px var(--bc-s-1);
  border-radius: var(--bc-r-xs);
  cursor: pointer;
}
.cp-school__select:focus-visible { outline: 2px solid var(--bc-accent-500); outline-offset: 1px; }

/* Below the tablet breakpoint the top bar is already carrying search, the
   environment chip and four buttons; the school name is the first thing that
   can afford to go, because every school screen also names the school in its
   own context strip. */
@media (max-width: 900px) {
  .cp-school { display: none; }
}



/* ── Brand lockup ─────────────────────────────────────────────────────────
   ClariPay never recolours its mark to match a province: the two marks sit
   side by side with a hairline between them, per the CI guidelines. */
.cp-brand { display: flex; align-items: center; gap: var(--bc-s-3); text-decoration: none; }
.cp-brand__mark { height: 28px; width: auto; display: block; }
.cp-brand__cobrand {
  display: flex; align-items: center; gap: var(--bc-s-3);
  padding-left: var(--bc-s-3);
  border-left: 1px solid rgba(255,255,255,.16);
}
.cp-brand__name {
  font-family: var(--bc-font-display);
  font-size: var(--bc-fs-lg);
  font-weight: var(--bc-fw-bold);
  letter-spacing: -.02em;
  color: var(--bc-white);
  line-height: 1.1;
}
.cp-brand__tag {
  display: block;
  font-size: var(--bc-fs-2xs);
  font-weight: var(--bc-fw-regular);
  letter-spacing: .01em;
  color: rgba(255,255,255,.55);
}


/* ── Vertical nav: section headings and role scoping ──────────────────────
   BCDF ships .bc-vnav__group; SFMS needs a slightly tighter rhythm because the
   MIS menu carries five groups on one screen. */
.bc-vnav__group:first-child { margin-top: 0; }
.bc-vnav__item form { margin: 0; width: 100%; }
.bc-vnav__item--button {
  width: 100%;
  border: 0;
  background: transparent;
  font: inherit;
  text-align: left;
  cursor: pointer;
}


/* ── KPI tile fixes ───────────────────────────────────────────────────────
   BCDF's .bc-kpi sets no display, which is correct for the <div> the framework
   ships — but a tile that drills down should be one big link, and an <a> is
   inline by default, which collapses the whole card. */
a.bc-kpi {
  display: block;
  color: inherit;
  text-decoration: none;
  transition: border-color var(--bc-transition), box-shadow var(--bc-transition);
}
a.bc-kpi:hover {
  border-color: var(--bc-accent-300);
  box-shadow: var(--bc-sh-sm);
}
.bc-kpi__icon { margin-bottom: var(--bc-s-3); }
.bc-kpi__icon i { font-size: 19px; line-height: 1; }

/* A badge is a label, not a column: never let a flex parent stretch it into an
   oval. Applies to both vocabularies while the compat layer still exists. */
.bc-badge, .badge, .cp-status { align-self: center; }


/* ── Toast host ───────────────────────────────────────────────────────────── */
#cp-toasts {
  position: fixed;
  right: var(--bc-s-6);
  bottom: var(--bc-s-6);
  z-index: var(--bc-z-toast);
  display: flex;
  flex-direction: column;
  gap: var(--bc-s-3);
}


/* ── Filterable select (replaces Select2) ─────────────────────────────────── */
.cp-filter-select { display: flex; flex-direction: column; gap: var(--bc-s-2); }
.cp-filter-select > select[size] { min-height: 160px; }


/* ── Page header ──────────────────────────────────────────────────────────
   Every list screen answers "where am I / what needs attention" in the same
   place. BCDF has .bc-pagehead; this adds the action slot SFMS screens use. */
.cp-pagehead {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--bc-s-4);
  flex-wrap: wrap;
  margin-bottom: var(--bc-s-6);
}
.cp-pagehead__actions { display: flex; align-items: center; gap: var(--bc-s-2); flex-wrap: wrap; }


/* ── Amount input ─────────────────────────────────────────────────────────
   A rand field is typed, read back and checked against a bank statement. It
   gets the money face and right alignment in the input itself, not just in the
   table it ends up in. */
.cp-amount, .amount-field input, input.amount-field {
  font-family: var(--bc-font-money);
  font-variant-numeric: tabular-nums;
  text-align: right;
  letter-spacing: -.01em;
}


/* ── Reduced motion ───────────────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  .bc-mis__aside { transition: none; }
}


/* ── Enterprise shell — SFMS additions ─────────────────────────────────────
   Keep the province co-brand lockup readable on the ink sidebar, and give the
   converted pages the same header spacing the mockups use inside .bce-content. */
.bce-side .cp-brand__cobrand { background: #fff; border-radius: 4px; padding: 2px 6px; display: inline-flex; }
.bce-content > .bce-page:first-child { margin-bottom: 20px; }
.bce-side__user form { margin: 0; }

/* ── Enterprise layer — SFMS extensions (candidates to upstream) ─────────────
   · .bce-segment styles <button> only; a filter that navigates is an <a>.
   · Utilisation bars need semantic fills, and a label-less variant for table cells. */
.bce-segment a { display: inline-flex; align-items: center; height: 30px; padding: 0 12px; background: var(--bc-bg-surface); color: var(--bc-text-body); font-size: var(--bc-fs-xs); font-weight: 500; text-decoration: none; border-right: 1px solid var(--bc-border-strong); }
.bce-segment a:last-child { border-right: 0; }
.bce-segment a.is-active { background: var(--bc-brand-600); color: #fff; }
.bce-segment a:hover:not(.is-active) { background: var(--bc-bg-sunken); text-decoration: none; }
.bce-hbar--cell { grid-template-columns: 1fr auto; }
td .bce-hbar { grid-template-columns: 1fr auto; }
.bce-hbar__fill.is-warn { background: var(--bc-warning); }
.bce-hbar__fill.is-bad  { background: var(--bc-danger); }
.bce-kpi__value .bce-money { font-size: inherit; font-weight: inherit; color: inherit; }
.bce-pagehead__title .bce-id { font-size: var(--bc-fs-sm); }
/* code block for voucher codes — read out over the phone, so big and spaced */
.cp-voucher-code { font-family: var(--bc-font-mono, ui-monospace, monospace); font-size: 22px; letter-spacing: .12em; font-weight: 600; color: var(--bc-text-strong); }

/* ── Row action buttons ───────────────────────────────────────────────────────
   Two .bc-btn elements side by side are inline-flex boxes, so the browser aligns
   them on their baselines. A button with a text label takes its baseline from
   that text; an icon-only button has no text line, so it falls back to its bottom
   margin edge. The two therefore sit at different heights — visible wherever a
   "Fund" button stands next to a pencil.

   Aligning box centres instead of baselines fixes every occurrence, including
   ones not yet written, without touching a single view. */
html .bc-btn,
html .btn { vertical-align: middle; }

/* Preferred for a cluster of row actions: a flex row cannot have the baseline
   problem by construction, and it replaces collapsed inter-tag whitespace with
   one deliberate gap. */
.bc-row-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--bc-s-2);
}

/* An icon-only button should be square rather than a label button with the label
   missing, so the pair reads as one control group. */
.bc-btn--xs.bc-btn--icon  { width: 30px; padding-inline: 0; }
.bc-btn--sm.bc-btn--icon  { width: 36px; padding-inline: 0; }

/* ── One-time wallet credentials ──────────────────────────────────────────────
   Deliberately not styled as an alert. Alerts are acknowledged and dismissed;
   this must be acted on before the page is left, because PayChain returns the
   temporary password once, stores only its hash, and never sends it to the
   holder. No auto-hide, no dismiss control. */
.cp-cred {
  border: 1px solid var(--bc-warning, #E2A03F);
  border-left-width: 4px;
  border-radius: var(--bc-r-md, 8px);
  background: var(--bc-bg-surface, #fff);
  padding: var(--bc-s-5, 20px);
  margin-bottom: var(--bc-s-6, 24px);
}
.cp-cred__head  { display: flex; align-items: center; gap: var(--bc-s-2, 8px); }
.cp-cred__title { font-weight: 600; color: var(--bc-text-strong, #102A43); }
.cp-cred__lede  { margin: var(--bc-s-2, 8px) 0 var(--bc-s-4, 16px);
                  color: var(--bc-text-body, #486581); font-size: 14px; max-width: 70ch; }

/* Label above value, not beside it: the value is the thing being copied, so it
   gets the full line and a monospace face where every character is unambiguous —
   an O and a 0 in a temporary password are not interchangeable. */
.cp-cred__grid  { display: flex; flex-wrap: wrap; gap: var(--bc-s-5, 20px); margin: 0; }
.cp-cred__grid dt { font-size: 12px; text-transform: uppercase; letter-spacing: .04em;
                    color: var(--bc-text-muted, #829AB1); margin-bottom: 4px; }
.cp-cred__grid dd { margin: 0 var(--bc-s-5, 20px) 0 0; }
.cp-cred__grid code {
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  font-size: 15px; font-weight: 600;
  color: var(--bc-text-strong, #102A43);
  background: var(--bc-grey-100, #F0F4F8);
  padding: 6px 10px; border-radius: 6px;
  user-select: all;                 /* one click selects the whole value */
}
.cp-cred__actions { display: flex; align-items: center; flex-wrap: wrap;
                    gap: var(--bc-s-3, 12px); margin-top: var(--bc-s-4, 16px); }
.cp-cred__note    { font-size: 13px; color: var(--bc-text-muted, #829AB1); }


/* ── Provincial dashboard: layout, position strip and charts ──────────────
   These live here rather than in claripay.mis-v2.css because that sheet is not
   in the _Layout load chain — its selectors are scoped to the retired `.bc-mis`
   shell, which the enterprise `.bce-` shell replaced. Chart primitives are
   reproduced here, unscoped, so the dashboard is styled by a stylesheet the
   page actually loads.

   No hex. Every colour is a token, so dark mode and per-province themes reach
   the charts without a second definition. */

/* Two working columns, main first. Below 1180px the supporting panel moves
   under the workspace rather than being squeezed into a column too narrow to
   hold a rand amount without breaking it at the decimal point. */
.cp-dash-2 {
  display: grid;
  gap: var(--bc-s-6, 24px);
  align-items: start;
  grid-template-columns: minmax(0, 1.6fr) minmax(300px, 1fr);
}
.cp-dash-2--even { grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (max-width: 1180px) {
  .cp-dash-2,
  .cp-dash-2--even { grid-template-columns: minmax(0, 1fr); }
}

/* The money position: a few named figures that belong to one another, read as
   one sentence. Deliberately not tiles — tiles claim headline status, and only
   the KPI row above gets that. */
.cp-flow {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: var(--bc-s-6, 24px);
}
.cp-flow__item { min-width: 0; }
.cp-flow__k {
  display: block;
  font-size: var(--bc-fs-xs, 12px);
  color: var(--bc-text-muted);
  text-transform: uppercase;
  letter-spacing: .04em;
}
.cp-flow__v {
  display: block;
  margin-top: var(--bc-s-2, 8px);
  font-family: var(--bc-font-money);
  font-size: 1.25rem;
  font-weight: var(--bc-fw-semi, 600);
  color: var(--bc-text-strong);
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}
.cp-flow__note { display: block; margin-top: 2px; font-size: var(--bc-fs-xs, 12px); color: var(--bc-text-muted); }

/* ── Charts ──────────────────────────────────────────────────────────────
   Every chart answers one stated question and names its period and its unit.
   The SVG sits in a scrollable wrapper so its 12px labels keep their size on a
   narrow screen instead of shrinking into illegibility with the viewport, and
   every chart is followed by a disclosure holding the exact figures. */
.cp-chart-wrap { overflow-x: auto; max-width: 100%; }
.cp-chart      { display: block; width: 100%; height: auto; min-width: 520px; overflow: visible; }
.cp-chart text { font-family: var(--bc-font-body); font-size: var(--bc-fs-xs, 12px); fill: var(--bc-text-muted); }

/* Hairline, solid, and a step off the surface — the grid is a reading aid, not
   a mark. Dashes would add a second texture competing with the data. */
.cp-gridline    { stroke: var(--bc-grey-100, var(--bc-border)); stroke-width: 1; }

.cp-chart-line  { fill: none; stroke: var(--bc-accent-500); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }

/* The hue itself at a tenth, not a pre-mixed pale blue. A wash composites
   correctly over whatever surface the card is on — including the dark theme,
   where a fixed --bc-accent-50 would sit on the page as a bright slab. */
.cp-chart-fill  { fill: var(--bc-accent-500); fill-opacity: .10; }

/* Filled in the series colour with a 2px ring in the SURFACE colour. The ring
   is what keeps a marker legible where it crosses the line or sits on the axis;
   a hollow dot reads as a hole punched in the chart and, at twelve of them,
   as a row of beads. */
.cp-chart-dot   { fill: var(--bc-accent-500); stroke: var(--bc-bg-surface); stroke-width: 2; }

/* No stroke, ever — see bridge §2.1b. Bars are separated by the gap between
   them, not by an outline drawn around each one. */
.cp-chart-bar   { fill: var(--bc-accent-500); }

/* Values wear TEXT tokens, not the series colour, and medium rather than
   semibold: these labels sit directly on the plot, where 600 competes with the
   mark it is annotating. */
.cp-chart-value,
.cp-chart-peak  { fill: var(--bc-text-body); font-weight: var(--bc-fw-medium, 500); font-variant-numeric: tabular-nums; }
.cp-chart-ylab  { font-variant-numeric: tabular-nums; }
.cp-chart-sub,
.cp-chart-unit  { fill: var(--bc-text-subtle, var(--bc-text-muted)); }

/* The unit caption names the axis; it is not a value on it. Letter-spaced and
   upper-case so it reads as a header even when it is one word long. */
.cp-chart-unit  { font-size: 11px; letter-spacing: .06em; text-transform: uppercase; }

/* A transparent disc over every point, so the tooltip has a target you can
   actually hit — the visible marker is 6px across and a mouse is not. */
.cp-chart-hit   { fill: transparent; stroke: none; cursor: default; }

/* The exact-figures disclosure under a chart. Native <details>, so it works
   with a keyboard and a screen reader without any script. */
.cp-chart-table { margin-top: var(--bc-s-4, 16px); }
.cp-chart-table > summary {
  min-height: 40px;
  display: inline-flex; align-items: center; gap: var(--bc-s-2, 8px);
  color: var(--bc-text-accent, var(--bc-accent-600));
  font-size: var(--bc-fs-base, 14px);
  cursor: pointer; list-style: none; width: max-content;
}
.cp-chart-table > summary::-webkit-details-marker { display: none; }
.cp-chart-table > summary::before { content: "+"; font-weight: var(--bc-fw-semi, 600); }
.cp-chart-table[open] > summary::before { content: "\2212"; }
.cp-chart-table > summary:hover { text-decoration: underline; }

/* ── Outstanding work ────────────────────────────────────────────────────
   One row per thing a person still has to do. The count leads, because the
   reader is deciding what to open next, not reading prose. */
.cp-todo { display: grid; }
.cp-todo__item {
  display: grid;
  grid-template-columns: 56px minmax(0, 1fr);
  gap: var(--bc-s-4, 16px);
  align-items: start;
  padding: var(--bc-s-5, 20px) 0;
  border-bottom: 1px solid var(--bc-border-subtle, var(--bc-border));
}
.cp-todo__item:first-child { padding-top: var(--bc-s-2, 8px); }
.cp-todo__item:last-child  { border-bottom: 0; padding-bottom: var(--bc-s-2, 8px); }
.cp-todo__n {
  font-family: var(--bc-font-money);
  font-size: 1.25rem;
  font-weight: var(--bc-fw-semi, 600);
  color: var(--bc-text-strong);
  font-variant-numeric: tabular-nums;
  line-height: 1.2;
}
.cp-todo__item--alert .cp-todo__n { color: var(--bc-danger, var(--bc-text-strong)); }
.cp-todo__t { font-size: var(--bc-fs-base, 14px); font-weight: var(--bc-fw-medium, 500); color: var(--bc-text-strong); }
.cp-todo__p { margin: 2px 0 var(--bc-s-2, 8px); font-size: var(--bc-fs-xs, 12px); color: var(--bc-text-muted); }
.cp-todo__done {
  display: flex; align-items: center; gap: var(--bc-s-2, 8px);
  padding: var(--bc-s-6, 24px) 0;
  color: var(--bc-text-muted); font-size: var(--bc-fs-base, 14px);
}

/* A labelled bar row — district and category breakdowns. The label sits above
   its own bar rather than beside it, so a long district name never squeezes
   the bar down to a stub on a narrow column. */
.cp-bars { display: grid; gap: var(--bc-s-5, 20px); }
.cp-bar__head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--bc-s-4, 16px); flex-wrap: wrap;
  margin-bottom: var(--bc-s-2, 8px);
}
.cp-bar__name { font-size: var(--bc-fs-base, 14px); color: var(--bc-text-strong); min-width: 0; overflow-wrap: anywhere; }
.cp-bar__meta { font-size: var(--bc-fs-xs, 12px); color: var(--bc-text-muted); }
.cp-bar__fig  { font-family: var(--bc-font-money); font-size: var(--bc-fs-base, 14px); font-variant-numeric: tabular-nums; color: var(--bc-text-strong); white-space: nowrap; }

/* Panels stacked inside one working column, on the same 24px rhythm as the
   columns themselves. */
.cp-stack { display: grid; gap: var(--bc-s-6, 24px); align-content: start; }


/* ── Buttons line up with the controls they act on ────────────────────────
   Two separate things were wrong wherever a form put a button beside a field,
   and both of them read as sloppiness rather than as a bug.

   1. THE BOXES WERE DIFFERENT SIZES. BCDF's text controls are 46px tall and
      .bc-btn is 44. Two pixels is invisible on its own and unmissable when the
      two sit side by side. The fields come down to 44 rather than the buttons
      going up to 46: 44 is the touch target the rest of the system is built
      on, .bc-btn--icon is already squared against it, and a slightly tighter
      field is the direction the MIS density work was going anyway.

   2. THE BUTTON WAS CENTRED AGAINST THE WRONG THING. .bc-row centres its
      children, so a button next to a LABELLED field is centred against the
      whole label-plus-gap-plus-control stack and ends up floating about 12px
      above the control it acts on — the gap visible on the payment queue's
      school chooser.

   .bc-bottom is the opt-in for new markup. The :has() rule is the safety net:
   it corrects every form already written without editing a hundred views. */

.bc-input, .bc-select { height: 44px; }

/* BCDF ships .bc-top and .bc-middle but never shipped the third one. */
.bc-bottom { align-items: flex-end; }

/* A field laid out along a row is not a field stacked in a form, and must not
   carry the stacked form's bottom margin — the margin is part of the flex item,
   so a bottom-aligned button would line up 20px below the control. */
.bc-row > .bc-field,
.bc-row > * > .bc-field:only-child { margin-bottom: 0; }

/* Only the buttons move. Everything else in the row keeps the alignment the
   view asked for. */
.bc-row:has(.bc-label) > .bc-btn,
.bc-row:has(.bc-label) > .btn,
.bc-row:has(.bc-label) > .btn-group { align-self: flex-end; }

/* Once the row wraps, the button is alone on its line: a stub button beside
   nothing looks like a mistake, so it takes the line. */
@media (max-width: 560px) {
  .bc-row.bc-wrap:has(.bc-label) > .bc-btn,
  .bc-row.bc-wrap:has(.bc-label) > .btn { width: 100%; }
}

/* An input that is itself a row item has to be allowed to share the line.
   .bc-input sets width:100%, which is right for a stacked form and wrong here:
   with flex-wrap on, an item wraps BEFORE it shrinks, so a full-width input
   pushes the button onto its own line even when there is room for both. */
.bc-row > .bc-input,
.bc-row > .bc-select { flex: 1 1 14rem; width: auto; min-width: 0; }


/* ── Searchable select ────────────────────────────────────────────────────
   The Select2 behaviour, built on the native <select> rather than replacing
   it (see the SEARCHABLE SELECT block in claripay.ui.js).

   There is deliberately almost no styling of the BUTTON here: it copies the
   native select's own className, so it is already a .bc-select, a .form-select,
   a .form-select-sm or the borderless .cp-province__select, and therefore
   already the right height, border and radius for wherever it sits. All this
   file adds is the text alignment a button does not get for free, and the
   panel — which has no native equivalent to inherit from. */

.cp-combo { position: relative; display: block; min-width: 0; }

/* The native select is still there, still named, still posting. It is taken
   out of the layout rather than display:none'd so that browser validation can
   still anchor its message to it, and it is not hidden from assistive tech
   until the button that replaces it is in place (.is-ready). */
.cp-combo.is-ready > .cp-combo__native {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; border: 0;
  clip-path: inset(50%); overflow: hidden; white-space: nowrap;
}

.cp-combo__btn {
  display: flex; align-items: center;
  text-align: left; cursor: pointer;
  font: inherit; font-size: var(--bc-fs-base);
}
/* The chevron comes from .bc-select / .form-select, which the button inherits;
   the value simply must not run underneath it. */
.cp-combo__btn > .cp-combo__value {
  flex: 1 1 auto; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* The prompt row ("— Select a school —") is a prompt, not a value. */
.cp-combo.is-empty > .cp-combo__btn { color: var(--bc-text-subtle); }
.cp-combo.is-open  > .cp-combo__btn { border-color: var(--bc-accent-500); box-shadow: var(--bc-focus-ring); }

.cp-combo__panel {
  position: absolute; z-index: var(--bc-z-drawer, 400);
  top: calc(100% + 4px); left: 0; right: 0;
  min-width: 240px;
  padding: var(--bc-s-2);
  background: var(--bc-bg-surface);
  border: 1px solid var(--bc-border-strong);
  border-radius: var(--bc-r-ctrl);
  box-shadow: var(--bc-sh-lg);
}

.cp-combo__search {
  width: 100%; height: 36px;
  padding: 0 var(--bc-s-3);
  font: inherit; font-size: var(--bc-fs-base);
  color: var(--bc-text-strong);
  background: var(--bc-bg-surface);
  border: 1px solid var(--bc-border-strong);
  border-radius: var(--bc-r-ctrl);
}
.cp-combo__search:focus { outline: none; border-color: var(--bc-accent-500); box-shadow: var(--bc-focus-ring); }

.cp-combo__list {
  list-style: none; margin: var(--bc-s-2) 0 0; padding: 0;
  max-height: 280px; overflow-y: auto;
}
.cp-combo__opt {
  padding: var(--bc-s-2) var(--bc-s-3);
  min-height: 36px; display: flex; align-items: center;
  font-size: var(--bc-fs-base); color: var(--bc-text-body);
  border-radius: var(--bc-r-sm);
  cursor: pointer;
}
/* One highlight, driven by the keyboard and by hover alike, so arrowing down
   and moving the mouse do not disagree about which row is next. */
.cp-combo__opt:hover,
.cp-combo__opt.is-active { background: var(--bc-bg-sunken); color: var(--bc-text-strong); }
.cp-combo__opt.is-selected { font-weight: var(--bc-fw-semi); color: var(--bc-text-strong); }
.cp-combo__opt[aria-disabled="true"] { color: var(--bc-text-subtle); cursor: default; }

.cp-combo__note {
  margin: var(--bc-s-2) 0 var(--bc-s-1);
  padding: 0 var(--bc-s-3);
  font-size: var(--bc-fs-xs); color: var(--bc-text-muted);
}

/* In the top bar the control is a pill sitting at the right-hand edge, so the
   panel hangs from its right edge and takes the width it needs. */
.cp-province .cp-combo__panel,
.cp-school .cp-combo__panel { left: auto; right: 0; width: 280px; }

/* Without JavaScript nothing above exists and the page is a plain select. */

/* The combobox wrapper takes the place of the select as the row item, so it
   inherits the sizing the select had (see the control-alignment block above). */
.bc-row > .cp-combo { flex: 1 1 14rem; min-width: 0; }


/* ── Money is one token ───────────────────────────────────────────────────
   en-ZA groups thousands with a SPACE, so a narrow column will happily break
   "R1 332 260 000.00" after "R1 332" and leave a reader looking at a number
   that says something else entirely. Nothing in BCDF stopped that; this does.
   Tables already scroll inside .bc-table-wrap, so nothing is cut off. */
.bc-money,
.bc-table__num,
.cp-flow__v,
.cp-todo__n { white-space: nowrap; }

/* ── Configuration sub-navigation ────────────────────────────────────────
   The seven configuration screens used to have no way between them: the
   sidebar's single "Configuration" item drops you on one of them and every
   one of the seven links only within itself. Five of those screens are
   authorised for a ProvinceAdmin, so the practical effect was a role that
   could configure quintiles and funding rates in principle and could not
   reach either screen by clicking.

   A row of links rather than a second sidebar level: these are siblings you
   move between while setting one thing up, not a hierarchy you descend. It
   scrolls rather than wraps, because a tab strip that reflows to two lines
   stops reading as one group — and the active tab keeps its scroll position
   on a narrow screen, which a wrapped row cannot. */
.cp-subnav {
  display: flex;
  gap: 4px;
  overflow-x: auto;
  scrollbar-width: none;
  padding-bottom: 2px;
  margin-bottom: var(--bc-s-5, 20px);
  border-bottom: 1px solid var(--bc-border);
}
.cp-subnav::-webkit-scrollbar { display: none; }

.cp-subnav__item {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  white-space: nowrap;
  padding: 9px 13px;
  border-radius: 9px 9px 0 0;
  font-size: var(--bc-fs-sm, 13px);
  font-weight: var(--bc-fw-medium, 500);
  color: var(--bc-text-muted);
  text-decoration: none;

  /* The active underline is drawn on every tab and made transparent on the
     inactive ones, so selecting a tab changes a colour and never a height —
     a border that appears only when active shifts the whole row by 2px. */
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  transition: color .15s ease, background .15s ease, border-color .15s ease;
}

.cp-subnav__item i { font-size: 1rem; opacity: .85; }

.cp-subnav__item:hover {
  color: var(--bc-text-body);
  background: var(--bc-grey-50, #f7f9fb);
}

.cp-subnav__item.is-active {
  color: var(--bc-text-accent, var(--bc-accent-600));
  border-bottom-color: var(--bc-accent-500);
  background: transparent;
}
.cp-subnav__item.is-active i { opacity: 1; }

/* KPI row outside the MIS v2 shell. .cp-kpis was only defined under .bc-mis, and
   that stylesheet is not loaded on the enterprise layout, so the four figures on
   the School accounts page stacked full width down the page. */
.cp-kpis { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--bc-s-4, 16px); margin-bottom: var(--bc-s-6, 24px); }
.cp-kpis--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.cp-kpis--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (max-width: 1100px) { .cp-kpis, .cp-kpis--3 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 640px)  { .cp-kpis, .cp-kpis--2, .cp-kpis--3 { grid-template-columns: 1fr; } }

/* ── Manual budget: split by category ─────────────────────────────────────
   The manual budget dialog asks two questions — how much, then how it divides —
   so the split is its own group under a rule, with room above it, rather than
   more fields stacked onto the amount. */
.cp-split {
  margin-top: var(--bc-s-7, 32px);
  padding-top: var(--bc-s-6, 24px);
  border-top: 1px solid var(--bc-border-subtle);
}
.cp-split__head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--bc-s-4, 16px); flex-wrap: wrap;
  margin-bottom: var(--bc-s-4, 16px);
}
.cp-split__head > div:first-child { flex: 1 1 320px; min-width: 0; }
.cp-split__title {
  margin: 0 0 var(--bc-s-1, 4px);
  font-size: var(--bc-fs-base); font-weight: var(--bc-fw-semi);
  color: var(--bc-text-strong);
}
.cp-split__table td { vertical-align: middle; }
.cp-split__table th.bc-right { text-align: right; }
.cp-split__input { max-width: 210px; margin-left: auto; }
.cp-split__input .bc-input { min-width: 0; }
.cp-split__sum {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--bc-s-3, 12px); flex-wrap: wrap;
  margin-top: var(--bc-s-4, 16px);
  padding: var(--bc-s-3, 12px) var(--bc-s-4, 16px);
  border-radius: var(--bc-r-sm);
  background: var(--bc-grey-25, #fafbfc);
  border: 1px solid var(--bc-border-subtle);
}
.cp-split__sum .bc-money { white-space: nowrap; }
.cp-split__sum.is-ok  { background: var(--bc-success-bg); border-color: transparent; }
.cp-split__sum.is-ok  #manualSplitState { color: var(--bc-success-fg); }
.cp-split__sum.is-off { background: var(--bc-danger-bg);  border-color: transparent; }
.cp-split__sum.is-off #manualSplitState { color: var(--bc-danger-fg); }

/* Phone: the amount box needs the width more than the derived share does. */
@media (max-width: 640px) {
  .cp-split__share { display: none; }
  .cp-split__input { max-width: none; min-width: 9.5rem; }
}

/* The "split by hand" note on the Manual budget card. */
.cp-split-note {
  padding: var(--bc-s-3, 12px) var(--bc-s-4, 16px);
  border-radius: var(--bc-r-sm);
  background: var(--bc-grey-25, #fafbfc);
  border: 1px solid var(--bc-border-subtle);
}

/* App link inside the one-time credentials panel — long Azure URLs must wrap, not
   push the panel wider than the page. */
.cp-cred__link { word-break: break-all; font-weight: 600; }
