/* ==========================================================================
   paychain.bridge.css — SmartSuite Finance template ➜ PayChain MIS
   --------------------------------------------------------------------------
   Ported from SFMS.Web/wwwroot/css/claripay.bridge.css, 22 Sep 2026. The
   collision patches in §2–6 are that file's, unchanged apart from naming,
   because they fix collisions between two stylesheets that are identical in
   both products. Section 1 is PayChain's, and was rebuilt the same day on the
   PayChain Corporate Identity Guidelines v1.0.

   WHAT THIS FILE IS FOR

   The MIS loads the SmartSuite Finance design system (~/design/*.css) on top
   of the BCDF Enterprise stack it was built on. Two complete design systems in
   one document, so two things have to happen and this is the only file that
   does either:

     1  TOKEN REMAP.  BCDF reads everything through --bc-* custom properties.
        Re-point those at the --brand-* values from ~/design/brand.css and
        every .bc-*, .bce-* and bootstrap-compat component in all ~170
        unconverted views adopts the palette without a single selector being
        touched. That is the whole reason the reskin is affordable, and it is
        why Transactions, Settlements, AML and the rest were not edited.

     2  COLLISION PATCH.  finance.css carries bare-element rules (svg, main,
        nav, footer, h1, h2) and generic class names (.progress, .panel,
        .metrics, .status, .tag, .primary, .ghost, .avatar) that the MIS
        already uses for something else. Each patch below names the collision
        it is fixing. Nothing there is decoration; if you cannot find the
        collision, the rule should not exist.

   LOAD LAST, immediately before the <style id="domain-accent"> block that
   _CommonMasterLayout emits for domain-scoped roles.

   Selector is .theme-enterprise, the class this product puts on <html>, plus
   :root so the auth screens get the palette too.
   ========================================================================== */


/* ==========================================================================
   1 · TOKEN REMAP — BCDF scales rebuilt on the PayChain CI
   ==========================================================================
   Same token names as enterprise.css, same ordering, CI values.

   THE ACCENT SCALE IS GOLD, AND GOLD IS A FILL, NOT A TYPEFACE COLOUR.
   The CI measures Trust Gold on Ivory at 2.76:1 and rules it out for body
   text. So --bc-text-accent does NOT point at the accent scale the way it did
   under cobalt; it points at --bc-accent-800, a deepened gold that clears 4.5:1
   on ivory. Every filled gold surface takes Obsidian ink via
   --cp-ink-on-accent. Get this wrong and every link in the product becomes
   unreadable at exactly the moment it looks fine on your own screen.
   ========================================================================== */
:root,
.theme-enterprise {

  /* ── Brand scale — Obsidian (#111111) ──────────────────────────────────
     Chrome and type. 600 is the CI obsidian; the rest are the warm-neutral
     steps around it, pulled toward Stone rather than a cool grey so they sit
     on Ivory without going blue. */
  --bc-brand-50:  #F7F5F0;
  --bc-brand-100: #E4DED2;   /* CI Mist */
  --bc-brand-200: #CFC8BA;
  --bc-brand-300: #A9A398;
  --bc-brand-400: #6E6A63;   /* CI Stone */
  --bc-brand-500: #3A3833;
  --bc-brand-600: #111111;   /* OBSIDIAN — primary chrome */
  --bc-brand-700: #0D0D0D;
  --bc-brand-800: #0A0A0A;
  --bc-brand-900: #050505;

  /* ── Accent scale — Trust Gold (#B58A45) ───────────────────────────────
     500 is the CI gold. 600/700 DARKEN for hover and active: contrast must
     improve on the element about to be clicked, not decay. 800 is the text
     gold — the only one allowed to carry type on ivory (4.61:1). */
  --bc-accent-50:  #FBF7EF;
  --bc-accent-100: #F1E7D2;
  --bc-accent-200: #E4D0AB;
  --bc-accent-300: #D8BC85;   /* CI Gold Light — for DARK surfaces */
  --bc-accent-400: #C6A263;
  --bc-accent-500: #B58A45;   /* TRUST GOLD — brand accent, primary fill */
  --bc-accent-600: #9C7538;   /* hover */
  --bc-accent-700: #83612C;   /* active */
  --bc-accent-800: #6B4E22;   /* TEXT gold — 4.61:1 on Ivory, links and small type */
  --bc-accent-900: #4A3617;

  /* Ink on a filled accent surface. Gold is light, so this is Obsidian — the
     CI's own rule: "Primary action: Trust Gold fill with Obsidian text." The
     domain-accent block recomputes it per domain from relative luminance, so a
     domain that picks a dark navy gets white type instead. It must exist here
     even with no domain applied: without it var() resolves to nothing, `color`
     becomes invalid at computed-value time, and the button label inherits a
     colour indistinguishable from the button behind it. */
  --cp-ink-on-accent: #111111;

  /* Text gold. NOT the accent scale's 500 — Trust Gold on Ivory is 2.76:1 and
     the CI forbids it for type. This is accent-800 at 6.74:1, and it is what
     every link, every .text-primary and every small accent label resolves to.
     Verified against the CI's own published pairings, which this ramp
     reproduces exactly: Trust Gold on Ivory 2.76, Obsidian on Trust Gold 6.01,
     Ivory on Obsidian 16.60, Gold Light on Obsidian 10.30, Stone on Ivory 4.73. */
  --bc-text-accent: var(--bc-accent-800);

  /* ── Support scale — money that went right ─────────────────────────────
     Built around the CI's functional success green so a BCDF success pill and
     a template .green-tag are the same green. */
  --bc-support-50:  #E8F3EE;
  --bc-support-100: #C8E3D6;
  --bc-support-200: #97CBB1;
  --bc-support-300: #4FA383;
  --bc-support-400: #2A8A65;
  --bc-support-500: #1E7A55;   /* CI success */

  /* ── Neutrals — the CI's warm ramp ─────────────────────────────────────
     --bc-grey-50 is the application background and MUST equal --brand-canvas,
     or every BCDF surface sits on a different white to every template panel.
     --bc-grey-200 is the border and is CI Mist. Those two are load-bearing;
     the rest are the ramp between them. This ramp is WARM — the previous one
     was cool grey, and mixing the two is what makes an ivory page look dirty. */
  --bc-grey-25:  #FBFAF6;
  --bc-grey-50:  #F4F0E7;    /* = --brand-canvas, CI Ivory */
  --bc-grey-100: #EDE8DC;
  --bc-grey-200: #E4DED2;    /* CI Mist — borders and dividers */
  --bc-grey-300: #CFC8BA;
  --bc-grey-400: #9A948A;
  --bc-grey-500: #6E6A63;    /* CI Stone — muted text, 4.73:1 on Ivory */
  --bc-grey-600: #585550;
  --bc-grey-700: #3A3833;
  --bc-grey-800: #232220;
  --bc-grey-900: #111111;

  /* ── Semantic — the CI's functional interface colours ──────────────────
     "Functional interface colours may communicate state but never replace the
     core brand palette." They do not follow a domain's white-label: red means
     one thing in every domain. The -bg and -fg steps are derived so a filled
     chip and its text pass AA on ivory. */
  --bc-success:    #1E7A55;
  --bc-success-bg: #E8F3EE;
  --bc-success-fg: #166044;

  --bc-warning:    #A66A14;
  --bc-warning-bg: #FBF0DF;
  --bc-warning-fg: #855410;   /* warning type is never the fill colour */

  --bc-danger:     #B53A3A;
  --bc-danger-bg:  #F9EAEA;
  --bc-danger-fg:  #932E2E;

  --bc-info:       #2D66C3;
  --bc-info-bg:    #E8EFFA;
  --bc-info-fg:    #24519C;

  --bc-neutral-bg: #EDE8DC;
  --bc-neutral-fg: #6E6A63;

  --bc-purple:     #6E6A63;   /* the CI has no purple; Stone carries these */
  --bc-purple-bg:  #EFEDE8;
  --bc-purple-fg:  #4A4843;

  /* ── The insight point ─────────────────────────────────────────────────
     The "look here" colour on a dark surface is Gold Light, which is what the
     CI's value path is. Fill only — never type, never a button. */
  --bc-insight:      #D8BC85;
  --bc-insight-bg:   #FBF7EF;
  --bc-insight-ink:  var(--bc-brand-600);

  /* ── Focus ─────────────────────────────────────────────────────────────
     readability.css sets :focus-visible{outline:3px solid var(--blue)} for
     template components and BCDF uses a box-shadow ring; both now point at
     gold. The CI requires a visible keyboard focus on every control. */
  --bc-focus-ring: 0 0 0 3px rgba(181, 138, 69, .38);

  /* ── Typography — Inter, per the CI ────────────────────────────────────
     The CI names Inter as the primary family with an Arial / Nimbus Sans
     fallback, so the DM Sans + Manrope pairing the SFMS template shipped with
     is NOT used here. Inter carries both display and body; it is already
     self-hosted in this project. IBM Plex Mono stays for money and audit IDs:
     the CI asks for tabular figures on money, rates, counts and timestamps,
     and a column of rands in a proportional face does not line up. */
  --bc-font-display: "Inter", Arial, "Nimbus Sans", sans-serif;
  --bc-font-body:    "Inter", Arial, "Nimbus Sans", sans-serif;
  --bc-font-mono:    "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  --bc-font-money:   "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  /* ── Shape — the CI's radii, which are tighter than the template's ─────
     Control 8px, card 12px, status chip full-round. The SmartSuite template
     runs 10–17px; the CI wins, because radius is the cheapest way for a
     product to stop looking like its own brand. */
  --bc-radius-sm: 6px;
  --bc-radius:    8px;    /* CI control radius */
  --bc-radius-md: 10px;
  --bc-radius-lg: 12px;   /* CI card radius */
  --bc-radius-xl: 16px;

  /* "Use one subtle elevation level only when hierarchy requires it." Panels
     are flat with a 1px Mist line; the shadow is reserved for things that
     genuinely float — drawer, palette, toast. */
  --bc-shadow-xs: none;
  --bc-shadow-sm: none;
  --bc-shadow:    0 12px 32px rgba(17, 17, 17, .10);
  --bc-shadow-lg: 0 28px 80px rgba(17, 17, 17, .28);

  /* ── Motion — CI durations and easing ──────────────────────────────────
     150ms micro, 220ms standard, 320ms major, ease-out. */
  --bc-motion-micro:    150ms;
  --bc-motion-standard: 220ms;
  --bc-motion-major:    320ms;
  --bc-ease-out: cubic-bezier(0.2, 0.8, 0.2, 1);
}


/* --------------------------------------------------------------------------
   1b · WHERE THE TEMPLATE ASSUMED A DARK-BLUE CHROME

   finance.css builds its dark surfaces out of hand-mixed navy hexes rather
   than tokens (#0a2030, #112c3e, #0b2232, #244052 and friends). Under a navy
   ink those blended invisibly; under Obsidian they read as blue patches on a
   black sidebar. These re-point the ones that actually show.
   -------------------------------------------------------------------------- */
/* --brand-accent-rgb / --brand-primary-rgb are declared here so the two decoration
   tints below resolve with no domain applied. MisDomainTheme.BuildTokenOverride
   re-emits BOTH, which is what lets a domain's colour reach the active nav rule —
   these used to be literal Trust Gold, and a TipTapPay admin got a gold active
   item on their own sidebar with nothing on screen to explain why. */
:root, .theme-enterprise {
  --brand-accent-rgb:  216, 188, 133;   /* Gold Light */
  --brand-primary-rgb: 181, 138, 69;    /* Trust Gold */
}

.sidebar { background: linear-gradient(180deg, var(--brand-ink), #1C1A17) !important; }
.sidebar .nav-item:hover { background: #211F1B; }
.sidebar .nav-item.active {
  background: linear-gradient(90deg,
                rgba(var(--brand-primary-rgb), .26),
                rgba(var(--brand-accent-rgb), .06));
  box-shadow: inset 2px 0 var(--brand-accent);
}
.sidebar .suite-switch { background: #1A1815; border-color: #2E2B26; }
.sidebar .control-card { background: #1A1815; border-color: #2E2B26; }
.sidebar .crest { background: linear-gradient(145deg, var(--brand-accent), var(--brand-primary)); color: #111; }
.treasury-panel,
.budget-hero,
.bank-strip,
.featured-report {
  background: radial-gradient(circle at 80% 0, rgba(var(--brand-accent-rgb), .18), transparent 38%),
              linear-gradient(145deg, var(--brand-ink), #1C1A17) !important;
}
.metrics .dark-metric { background: linear-gradient(145deg, #15140F, #1C1A17); border-color: #2E2B26; }
.drawer-stat, .toast { background: #1A1815; }


/* ==========================================================================
   2 · COLLISION PATCHES
   ==========================================================================
   Each block names the finance.css / finance-pages.css rule it is undoing and
   why the MIS needs it undone. In load order of severity.
   ========================================================================== */

/* --------------------------------------------------------------------------
   2.1  The bare `svg` rule.  THE WORST ONE.

   finance.css:  svg{width:20px;height:20px;fill:none;stroke:currentColor;
                     stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}

   Every icon in the MIS is <svg class="bc-i"><use href="#i-…"/></svg> drawn from
   brookscorp-icons.js and bce-icons.js, and a good half of that sprite is
   FILLED geometry, not stroked paths. The bare rule forces fill:none on all of
   them, so those icons render as nothing at all — an invisible button. It also
   pins every icon to 20px, destroying .bc-i--sm / --lg and the 28px sidebar
   marks.

   The template's own icons live in the inline sprite in _Layout and are all
   stroked, so they keep the rule; .bc-i takes its sizing and paint back.
   -------------------------------------------------------------------------- */
svg.bc-i {
  width: var(--bc-i-size, 1.25em);
  height: var(--bc-i-size, 1.25em);
  fill: currentColor;
  stroke: none;
  stroke-width: initial;
  flex: none;
}
/* The subset of the the MIS sprite that IS stroked opts back in. These are the
   ids drawn as outlines in bce-icons.js; everything else is filled. */
svg.bc-i.bc-i--stroke {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
/* --------------------------------------------------------------------------
   2.1b  The same bare `svg` rule, reaching the dashboard CHARTS.

   This one does its damage through INHERITANCE rather than directly, which is
   why it went unnoticed while §2.1 was being written. `stroke` and
   `stroke-width` are INHERITED SVG properties, so
   `svg{stroke:currentColor;stroke-width:1.8}` lands on every child of
   `<svg class="cp-chart">` that does not declare its own — every `<text>`, every
   bar, the area fill under the line.

   A 1.8px stroke around 12px type is what made the axis labels look heavy and
   faintly ragged: they were never bold, they were OUTLINED. The same stroke is
   the dark edge that appeared around each bar of the utilisation histogram, and
   `paychain.app.css` never asked for either. The marks that DO declare a stroke
   — the line, the dots, the gridlines — were unaffected, which is why only part
   of each chart looked wrong and the cause was easy to misread as a font weight.

   Resetting once on the root is enough. The children that want a stroke set one
   themselves; everything else now inherits `none`.
   -------------------------------------------------------------------------- */
svg.cp-chart { stroke: none; stroke-width: initial; }

svg.bc-i--sm { --bc-i-size: 1rem; }
svg.bc-i--lg { --bc-i-size: 1.5rem; }
svg.bc-i--xl { --bc-i-size: 2rem; }

/* RemixIcon is a FONT, not an svg — untouched by the above, but the bare
   `button,a{font:inherit}` rule strips the icon font off any <i class="ri-…">
   sitting inside a button. Put it back. */
[class^="ri-"], [class*=" ri-"] { font-family: remixicon !important; font-style: normal; }


/* --------------------------------------------------------------------------
   2.2  `main` and the sidebar gutter.

   finance.css:     main{margin-left:260px}
   readability.css: .sidebar{width:290px} .sidebar+main{margin-left:290px}

   Both assume the template's own <aside class="sidebar"> is the only aside on
   the page and that <main> is its sibling. The new _Layout satisfies that, so
   the rules are correct — but the MIS views also contain nested <main> elements
   in two print/export partials, which would each inherit a 290px gutter and
   push their content off the page. Only the shell's own main takes the gutter.
   -------------------------------------------------------------------------- */
main main,
.page main { margin-left: 0; }


/* --------------------------------------------------------------------------
   2.3  `nav{flex:1}`.

   Intended for the sidebar's single <nav>. the MIS views use <nav> for breadcrumb
   trails, tab strips and pagination, all of which become flex:1 children and
   stretch to fill their row. Scope the rule to the sidebar.
   -------------------------------------------------------------------------- */
.page nav { flex: initial; }


/* --------------------------------------------------------------------------
   2.4  `.progress`.

   finance.css:        .progress{height:5px;…}  .progress i{…the fill…}
   bootstrap-compat:   .progress{…}             .progress-bar{…the fill…}

   Same class, different child. finance.css loads later and wins, so every
   bootstrap progress bar in the MIS becomes a 5px empty track with an unstyled
   .progress-bar inside it — the bar disappears and the number it was showing
   goes with it. Give .progress-bar the same treatment .progress i gets.
   -------------------------------------------------------------------------- */
.progress > .progress-bar {
  display: block;
  height: 100%;
  background: linear-gradient(90deg, var(--brand-primary), #43c8d3);
  border-radius: 4px;
  transition: width var(--motion-enter, 360ms) var(--ease-out, cubic-bezier(.22,1,.36,1));
}
/* A bootstrap progress that carries a label inside the bar needs room for it;
   the 5px template track is for the bare ones. */
.progress:has(> .progress-bar:not(:empty)) { height: auto; min-height: 1.25rem; }
.progress > .progress-bar:not(:empty) {
  display: grid; place-items: center;
  color: #fff; font: 700 .75rem/1 Manrope, sans-serif;
  padding: .2rem .5rem;
}


/* --------------------------------------------------------------------------
   2.5  `.panel`, `.metrics`, `.status`, `.tag`, `.primary`, `.ghost`,
        `.secondary`, `.avatar`, `.toast`, `.eyebrow`, `.active`.

   These are the template's own component names and the MIS has no class of the
   same name — EXCEPT `.active`, which bootstrap-compat uses on nav links and
   pagination, and `.toast`, which paychain.app.css uses for the flash host.

   `.active` in finance-pages.css only ever appears compounded
   (.view-page.active, .orbit-view.active, .directory-view.active), so it is
   inert here and needs nothing.

   `.toast` is a real collision: the template styles a fixed bottom-right card
   and paychain.app.css styles a stacking host in the same corner. The template
   owns #toast (one element, in _Layout); the the MIS flash host is .cp-toast-host
   and its children are .cp-toast. Namespacing the the MIS side is a one-line fix
   applied in paychain.app.css, so all this file does is make sure the
   template's #toast is the specific one.
   -------------------------------------------------------------------------- */
.toast:not(#toast) { position: static; transform: none; opacity: 1; box-shadow: none; }


/* --------------------------------------------------------------------------
   2.6  `footer`.

   finance.css: footer{display:flex;justify-content:space-between;…}

   The shell footer wants that. Card footers, modal footers and .bc-card__foot
   inside views do not — several are grids, and flex silently collapses their
   columns into a row. Only the shell's own footer is a flex row.
   -------------------------------------------------------------------------- */
.page > footer { display: flex; }
.page main footer,
.page .panel footer,
.page .bc-card footer { display: revert; justify-content: revert; padding: revert; color: revert; }


/* --------------------------------------------------------------------------
   2.7  Headings.

   finance.css: h1,h2{font-family:Manrope;margin:0;letter-spacing:-.035em}
                h1{font-size:1.75rem}

   Wanted — but `margin:0` on every h1/h2 in every view removes the spacing
   those views were laid out with, and h3–h6 are left on the old face, so a
   page with an h2 and an h3 shows two different typefaces one line apart.
   Finish the job and give body copy its margins back.
   -------------------------------------------------------------------------- */
h3, h4, h5, h6,
.h3, .h4, .h5, .h6 { font-family: var(--bc-font-display); letter-spacing: -.02em; }

.cp-content > h2, .cp-content > h3, .cp-content > h4,
.cp-content > section > h2, .cp-content > section > h3 { margin-block: 1.5rem .5rem; }
.cp-content > h2:first-child,
.cp-content > h3:first-child, .cp-content > h4:first-child { margin-block-start: 0; }
.cp-content > p, .cp-content > ul, .cp-content > ol { margin-block: 0 1rem; }


/* ==========================================================================
   3 · CARRYING THE TEMPLATE'S LOOK INTO THE BCDF COMPONENTS
   ==========================================================================
   The token remap does the colours. These are the handful of places where the
   two systems draw the same object with genuinely different geometry, and the
   template's version has to win or the page reads as two designs stapled
   together.
   ========================================================================== */

/* 3.1  Surfaces. A .bc-card and a .panel appear side by side constantly —
        on the allocation detail screen, in every school record. They must be
        indistinguishable: same white, same 1px line, same 14px radius, same
        19px padding, no shadow. */
.bc-card, .bce-card, .card, .bce-panel {
  background: #fff;
  border: 1px solid var(--bc-grey-200);
  border-radius: var(--bc-radius-lg);
  box-shadow: none;
}
.bc-card__body, .card-body { padding: 19px; }
.bc-card__head, .card-header {
  padding: 19px 19px 0;
  background: none;
  border-bottom: 0;
  font-family: var(--bc-font-display);
}

/* 3.2  Buttons.

   THE SIZE SCALE MUST SURVIVE. The first version of this block set
       .bc-btn, .btn { min-height: 40px; font-weight: 700; }
   which looks right on the two buttons the template actually has — its big
   dark .primary and white .ghost in the page head — and is wrong everywhere
   else in the MIS. BCDF ships a real scale (.bc-btn--xs, --sm at 36px, base,
   --lg) and bootstrap-compat ships another (.btn-sm at 30px, .btn-lg at 44px),
   and a blanket min-height OVERRIDES BOTH: every small button in every table
   row inflated to 40px and went bold, which is the bulk Mike flagged on the
   Budget Allocations rows — two 40px 700-weight buttons stacked inside a 56px
   table row, twice per domain, nine domains down the page.

   So: a lighter base, and the variants restored explicitly above it.
   600 not 700 — at 13px, 700 in Manrope reads as shouting, and a table of row
   actions is not where emphasis belongs. The dark fill and the drop shadow are
   what mark the primary action; weight does not have to do it as well. */
.bc-btn, .btn {
  min-height: 34px;
  border-radius: 8px;
  padding-inline: 13px;
  font-weight: 600;
  font-size: .8125rem;
  letter-spacing: .005em;
  gap: 6px;
}
/* The scale, put back — and stated as `height`, not `min-height`, because
   brookscorp.css and bootstrap-compat both size these with `height` and a
   min-height simply loses to it. That is why the first attempt at this block
   left .bc-btn--lg at 52px and .bc-btn--sm at 36px: the rules were being
   written, and ignored. Labels here are one or two words, which is the
   assumption a fixed height carries. */
.bc-btn--xs, .btn-xs     { height: 28px; min-height: 0; padding-inline: 9px;  font-size: .75rem;   border-radius: 6px; }
.bc-btn--sm, .btn-sm     { height: 32px; min-height: 0; padding-inline: 11px; font-size: .8125rem; border-radius: 7px; }
.bc-btn--lg, .btn-lg     { height: 42px; min-height: 0; padding-inline: 20px; font-size: .875rem;  border-radius: 9px; }
.bc-btn--icon, .btn-icon { padding-inline: 0; aspect-ratio: 1; }
/* Icons inside buttons were sized for a 40px control. */
.bc-btn .bc-i, .btn .bc-i        { font-size: 1em; }
.bc-btn--sm .bc-i, .btn-sm .bc-i { font-size: .9em; }

/* A button standing in a filter row is the exception: it acts ON the field
   beside it, so it matches the field's height rather than the button scale.
   That is the alignment rule from earlier this month and it still holds — the
   fields are 44px. Everywhere else the sleeker scale applies. */
.bc-row > .bc-btn, .bc-row > .btn, .bc-row > .btn-group > .btn { height: 44px; min-height: 44px; padding-inline: 16px; }

/* THE PRIMARY BUTTON IS TRUST GOLD WITH OBSIDIAN INK, NOT DARK INK.

   This is a place where the CI beats the template outright. The SmartSuite
   Finance template's primary action is its ink colour (finance.css:
   .primary{background:var(--ink)}), and this rule used to follow it so a BCDF
   button and a template button matched. The PayChain CI is explicit the other
   way: "Primary action: Trust Gold fill with Obsidian text."

   So gold it is, and the label colour comes from --cp-ink-on-accent rather than
   a hardcoded #fff — white on Trust Gold is 3.14:1 and fails, Obsidian is
   6.01:1 and passes. That token is recomputed per domain from relative
   luminance, so a domain that white-labels to a dark navy gets white type back
   automatically. Never hardcode this colour.

   Hover DARKENS to accent-600 (Obsidian on it is still 4.51:1). The CI's
   elevation rule is "one subtle level only when hierarchy requires it", so the
   shadow is lighter than the template's and tinted with Obsidian, not navy. */
.bc-btn--primary, .btn-primary {
  background: var(--bc-accent-500);
  border-color: var(--bc-accent-500);
  color: var(--cp-ink-on-accent);
  box-shadow: 0 4px 12px rgba(17, 17, 17, .12);
}
.bc-btn--primary:hover, .btn-primary:hover {
  background: var(--bc-accent-600);
  border-color: var(--bc-accent-600);
  color: var(--cp-ink-on-accent);
}
/* The template's own .primary / .approve buttons, for the screens written in
   template markup rather than BCDF. Same rule, same reason. */
.page .primary, .drawer-actions .approve {
  background: var(--bc-accent-500);
  color: var(--cp-ink-on-accent);
  box-shadow: 0 4px 12px rgba(17, 17, 17, .12);
}
.page .primary:hover, .drawer-actions .approve:hover { background: var(--bc-accent-600); }

/* Secondary action ON DARK, per the CI: "Gold Light border with Ivory text."
   Applies inside the sidebar, the dark panels and the auth brand panel. */
.sidebar .bc-btn--ghost,
.treasury-panel .bc-btn--ghost,
.auth-brand .bc-btn--ghost {
  border-color: var(--brand-accent);
  color: var(--brand-canvas);
  background: transparent;
}
/* Small primaries do not float. A drop shadow under a 30px button in a table
   row reads as a rendering artefact, not as elevation. */
.bc-btn--sm.bc-btn--primary, .btn-sm.btn-primary,
.bc-btn--xs.bc-btn--primary, .bc-table .bc-btn, .bc-table .btn, .table .btn { box-shadow: none; }

/* The template's secondary IS white with a grey line — not a tinted accent.
   The line is hairline-soft: at nine rows deep, a hard border on two buttons
   per row turns the actions column into a grid of boxes. */
.bc-btn--secondary, .bc-btn--ghost, .btn-secondary, .btn-outline-secondary {
  background: #fff;
  border: 1px solid #e2e9ee;
  color: var(--bc-brand-600);
  box-shadow: none;
}
.bc-btn--secondary:hover, .bc-btn--ghost:hover,
.btn-secondary:hover, .btn-outline-secondary:hover { background: #f7f9fa; border-color: #d3dde4; }

/* Outline buttons carrying a colour (btn-outline-primary/success/danger, the
   idiom the unconverted views use for row actions) keep their meaning in the
   LABEL and let the border recede. Two saturated outlines side by side in a
   table row is what made that column shout. */
.btn-outline-primary, .btn-outline-success, .btn-outline-danger,
.btn-outline-info, .btn-outline-warning {
  background: #fff;
  border-color: #e2e9ee;
  box-shadow: none;
}

/* ── HOVER MUST SET COLOUR, NOT JUST BACKGROUND ─────────────────────────────
   Mike: "white text on light background and can hardly see the text if
   hovered over". Measured: 1.11:1 — invisible.

   Bootstrap's outline button fills with its solid colour on hover and turns
   the label WHITE. The rules above changed the hover background to a pale
   tint for the sleeker look and left the inherited white text sitting on it.
   Changing one half of a paired rule; the same mistake as the page header and
   the button scale, and the reason every hover below now names its colour
   explicitly even where the inherited one happens to be right.

   Values are measured, not chosen by eye — each pairing below is ≥ 5.6:1, and
   hover.py in the harness re-checks all 32 variants. If you add a variant, add
   it there too; a hover state is exactly the thing nobody screenshots. */
.btn-outline-primary:hover, .btn-text-primary:hover {
  background: var(--bc-accent-50);  border-color: var(--bc-accent-200); color: #1354B8;
}
.btn-outline-info:hover {
  background: var(--bc-info-bg);    border-color: #d6e6fe;              color: #1354B8;
}
.btn-outline-success:hover {
  background: var(--bc-success-bg); border-color: #c6eddf;              color: #0A6E4E;
}
.btn-outline-danger:hover, .btn-text-danger:hover {
  background: var(--bc-danger-bg);  border-color: #fbd5da;              color: #A81D2B;
}
.btn-outline-warning:hover {
  background: var(--bc-warning-bg); border-color: #f1d9a8;              color: #8A5310;
}
/* Their rest states too: #C94455 danger text clears white at 4.73 but drops to
   4.28 the moment it sits on its own tint, so it is darkened at rest as well
   rather than changing colour under the cursor. */
.btn-outline-danger, .btn-text-danger, .bc-text-danger { color: #A81D2B; }
.btn-outline-success { color: #0A6E4E; }

/* Filled semantic buttons. White on #13A778 is 3.08:1 and on #0F8964 is 4.39 —
   both short of 4.5 at the 13px these buttons use. The FILL darkens; the
   semantic tokens stay where they are, because they also drive badges and
   alert tints where the ink sits on the pale side and is already fine. */
.btn-success, .bc-btn--success { background: #0E7A57; border-color: #0E7A57; color: #fff; }
.btn-success:hover, .bc-btn--success:hover { background: #0D7152; border-color: #0D7152; color: #fff; }
.btn-danger,  .bc-btn--danger  { background: #BE3546; border-color: #BE3546; color: #fff; }
.btn-danger:hover, .bc-btn--danger:hover { background: #A81D2B; border-color: #A81D2B; color: #fff; }
/* Amber never takes white — that rule predates this template and survives it. */
.btn-warning, .bc-btn--warning { background: var(--bc-warning); border-color: var(--bc-warning); color: var(--bc-brand-600); }
.btn-warning:hover, .bc-btn--warning:hover { background: #DA8C22; border-color: #DA8C22; color: var(--bc-brand-600); }

/* Accent stays available for the one-per-screen "do the money thing" button
   (Approve run, Dispatch, Fund wallet) — those views ask for .bc-btn--accent. */
/* --bc-accent-600, not -500. White on the brand blue #2579F5 is 4.09:1, and
   these labels are 13px/600 — not large text, so 4.5 is the bar and the brand
   value misses it. The token itself is NOT darkened: -500 is also the link
   colour, the focus ring and the badge tint, where it sits as ink on white or
   as a thin ring and is fine. Only the filled button, which is the one place
   white type lands on top of it, steps down a stop. */
.bc-btn--accent {
  background: var(--bc-accent-600);
  border-color: var(--bc-accent-600);
  color: var(--cp-ink-on-accent);
  box-shadow: 0 6px 14px rgba(37, 121, 245, .18);
}
.bc-btn--accent:hover { background: var(--bc-accent-700); border-color: var(--bc-accent-700); }

/* Two more that were sitting just under the line at rest, both by a hair —
   4.47 and 4.17. Small misses, but they are the label on a control, and the
   fix costs one shade. */
.btn-outline-warning, .btn-text-warning, .bc-text-warning { color: #8A5310; }
.btn-text-secondary, .bc-btn--text { color: var(--bc-grey-700); }
.btn-text-secondary:hover { background: var(--bc-grey-100); color: var(--bc-brand-600); }

/* The template's own two buttons keep their weight — they are page-level
   actions with room around them, and they are the reference the rest is
   calibrated against. */
.page-head .primary, .page-head .ghost, .head-actions .primary, .head-actions .ghost {
  font-weight: 700;
  font-size: .875rem;
}

/* 3.3  Controls. The alignment work from earlier this month set .bc-input /
        .bc-select to 44px so buttons and fields share a baseline; the template
        draws them at 38–40px with a 10px radius on #f7f9fa. Keep 44px — the
        alignment rules in paychain.app.css depend on it and 44px is the touch
        target readability.css asks for — and take the template's skin. */
.bc-input, .bc-select, .form-control, .form-select, .cp-combo__btn {
  border: 1px solid #dce4e9;
  border-radius: 10px;
  background: #f7f9fa;
  font-family: var(--bc-font-body);
}
.bc-input:focus, .bc-select:focus, .form-control:focus, .form-select:focus {
  background: #fff;
  border-color: var(--bc-accent-400);
  box-shadow: var(--bc-focus-ring);
}
.bc-label, .form-label {
  font: 700 .75rem/1.45 Manrope, sans-serif;
  letter-spacing: .04em;
  color: #60717f;
}
/* A filter row with four controls and three buttons fits a full-width card and
   does not fit a dashboard column or a 390px phone. It wraps rather than
   pushing the last button past the edge — the same fix the Allocation detail
   button row needed, applied to the row primitive instead of one screen. */
.bc-row { flex-wrap: wrap; }

/* 3.4  Tables. The template's row rhythm is a 1px top line, 10px padding,
        #f8fafb on hover, and a .75rem uppercase Manrope head with wide
        tracking — no fill behind it. BCDF shades its header. Match. */
.bc-table thead th, .table thead th, .bce-table thead th {
  background: none;
  border-bottom: 1px solid var(--bc-grey-200);
  font: 700 .75rem/1.45 Manrope, sans-serif;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: #94a0a8;
  padding: 0 8px 7px;
}
.bc-table tbody td, .table tbody td, .bce-table tbody td {
  border-top: 1px solid #edf0f2;
  border-bottom: 0;
  padding: 10px 8px;
  font-size: .875rem;
}
.bc-table tbody tr:hover, .table tbody tr:hover, .bce-table tbody tr:hover { background: #f8fafb; }
/* A BCDF table dropped into one of the template's dashboard columns can be
   wider than the column — the money cells below are nowrap, so the table's
   min-content width is the sum of its columns and there is nothing to give.
   It scrolls inside its own panel instead of widening the document. Scoped to
   .dashboard-grid ON PURPOSE: putting overflow on every .bc-card__body would
   clip the searchable-select popup wherever a filter row and a table share a
   card, which is every list screen in the MIS. */
.dashboard-grid .bc-card__body:has(> .bc-table),
.dashboard-grid .bc-card__body:has(> .table),
.dashboard-grid .panel:has(> .bc-table) { overflow-x: auto; }
/* …and the scroll only works if the column is allowed to be narrower than its
   content. A grid item defaults to min-width:auto, which resolves to the
   table's min-content width and pushes the whole document wide instead. This
   one line is what actually stops the horizontal page scroll; the overflow
   rule above only decides where the scrollbar goes. */
.dashboard-grid > *, .cp-dash-2 > *, .cp-dash-2--even > * { min-width: 0; }
/* Same problem one level out. readability.css gives .programme-head/.programme-row
   a 590px min-width and relies on .programme-panel{overflow:auto} to contain it.
   A view that puts programme rows in a plain .panel — which is the obvious thing
   to do, since .panel is what the template documents — has no scroll container,
   and on a phone those 590px push the whole document sideways. Give any panel
   holding them the container it is assuming. */
.panel:has(> .programme-row), .panel:has(> .programme-head),
.bc-card:has(> .programme-row), .bc-card__body:has(> .programme-row) { overflow-x: auto; }

/* And once more for a plain BCDF table in a plain card. Most views wrap theirs
   in .bc-table-wrap, which already scrolls; the ones that do not push the whole
   document sideways on a phone. The :not() clauses are the important part — a
   card body that also holds a <select> or a .cp-combo must NOT become a scroll
   container, because the searchable-select popup is positioned inside it and
   would be clipped to the card. That is every list screen's filter row, so this
   is the difference between a guard and a regression. */
.bc-card__body:has(> .bc-table):not(:has(select)):not(:has(.cp-combo)),
.bc-card__body:has(> .table):not(:has(select)):not(:has(.cp-combo)),
.bc-table-wrap { overflow-x: auto; }
/* Money columns keep the mono face and stay unwrapped — the en-ZA thousands
   separator is a space and "R1 332 260 000.00" will break after "R1 332"
   given the chance. Same fix as paychain.app.css, restated because the
   template's table rules reset white-space. */
.bc-money, .bc-table__num, td.bc-table__num, .cp-flow__v, .cp-todo__n {
  font-family: var(--bc-font-money);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* 3.4b  THE CRUSHED-FIGURES BUG. Read this before touching .bc-money.

   themes/paychain.css carries:
       .bc-money { word-spacing: -.22em; letter-spacing: -.01em; }
   That compensation exists for ONE reason: en-ZA groups thousands with a
   no-break space, and in IBM Plex Mono a space is a full monospace character,
   so "R1 332 260 000" came out with canyons between the groups. Pulling it
   back .22em made it read as one number.

   The template breaks the assumption it rests on. Several of its components
   set type with the `font:` SHORTHAND — `.metrics article > strong` is
   `font: 700 1.5rem Manrope` — and a shorthand resets font-family. So the
   headline figures now render in MANROPE, a proportional face whose space is
   about 5px at 24px… while word-spacing is still -.22em, which at that size
   is -5.28px. The separator is not narrowed, it is erased:
   "R1 332 260 000" renders as "R1332260000".

   The fix is not to weaken the compensation — in the tables, where Plex Mono
   really does apply, -.22em is still correct and those columns still line up.
   It is to switch it off exactly where the shorthand has taken the mono face
   away. Tabular figures carry the alignment instead, which Manrope has.

   The list below is exactly the template selectors that use `font:` — checked
   one by one against finance.css and finance-pages.css, not assumed. Anything
   that only sets font-size (.programme-row b, .table-row b, .drawer-stat b,
   .variance b, .close-items b, .programme-row small) KEEPS the mono face and
   therefore keeps the compensation; adding those here would open the canyons
   back up in the very places the rule was written for.

   If you add a template component that sets money type with `font:`, add its
   selector here or its figures will run together the same way. */
.metrics article > strong,
.metrics article > strong span,
.treasury-stats b,
.programme-row > strong,
.table-row > strong,
.queue-total b,
.score-ring b,
.ds-metric strong,
.variance strong,
.bank-account > strong {
  word-spacing: normal;
  letter-spacing: -.02em;
  font-variant-numeric: tabular-nums;
}

/* 3.5  Badges and pills. BCDF's .bc-badge and the template's .tag / .status
        are the same object; give them one geometry so a status column reads
        as one column. */
.bc-badge, .badge, .bce-badge {
  font: 700 .75rem/1.45 Manrope, sans-serif;
  font-style: normal;
  border-radius: 9px;
  padding: 3px 7px;
  width: max-content;
}

/* 3.6  Alerts. The template's one alert is .alert-strip — a warm strip with a
        square mark, not a tinted block with a left border. Bootstrap alerts
        across the MIS adopt its shape while keeping their semantic colour. */
.alert {
  border-radius: 12px;
  border: 1px solid;
  padding: 11px 14px;
  font-size: .875rem;
}
.alert-warning { background: #fff9ed; border-color: #f1d9a8; color: var(--bc-warning-fg); }
.alert-success { background: var(--bc-success-bg); border-color: #c6eddf; color: var(--bc-success-fg); }
.alert-danger  { background: var(--bc-danger-bg);  border-color: #fbd5da; color: var(--bc-danger-fg); }
.alert-info    { background: var(--bc-info-bg);    border-color: #d6e6fe; color: var(--bc-info-fg); }


/* ==========================================================================
   4 · THE SHELL'S OWN ADJUSTMENTS
   ==========================================================================
   The template shell is built for six workspace links. the MIS has up to twenty-
   one across five groups, plus a tenant card, plus two switcher components in
   the top bar. These are the consequences.
   ========================================================================== */

/* 4.1  The sidebar has to scroll its nav, not the whole aside, or the control
        card and the user block scroll away and sign-out becomes unreachable
        on a laptop. The template's .sidebar{overflow:auto} is replaced by a
        grid: six rows in DOM order — brand · operating context · nav ·
        control card · user block · powered-by — of which only the nav row
        flexes, so everything below it stays pinned to the bottom edge. */
.sidebar {
  overflow: hidden;
  display: grid;
  grid-template-rows: auto auto minmax(0, 1fr) auto auto auto;
}
.sidebar nav { overflow-y: auto; overscroll-behavior: contain; min-height: 0; }
.sidebar nav::-webkit-scrollbar { width: 6px; }
.sidebar nav::-webkit-scrollbar-thumb { background: #1d3b4d; border-radius: 3px; }

/* 4.1b  The the PayChain MIS mark.

   finance.css:    .brand img{width:145px;filter:brightness(0) invert(1)}
   components.css: .sidebar .brand img{filter:none;background:#fff;padding:6px}

   The SmartSuite wordmark is dark artwork on a dark sidebar, hence the invert
   in one sheet and the white plate in the other. the PayChain MIS ships a KNOCKOUT
   mark — already white — so inverting it turns it black and plating it white
   makes it invisible. Neither treatment applies; it is drawn as-is. */
.sidebar .brand img { filter: none; background: none; padding: 0; }

/* Two forms, two sizings, per the CI's own responsive rule.

   ALONE:       the reverse lockup at 145px, above the CI's 140px minimum. Set by
                WIDTH, because the lockup's minimum is expressed as a width and
                letting height drive it is how it silently drops under 140.
   CO-BRANDED:  the symbol at 34px, above its own 24px minimum, with the domain's
                or merchant's mark beside it behind a hairline rule. This is the
                CI's "move from primary lockup to symbol" case, not a compression
                of the lockup — the wordmark is dropped, never squeezed.

   Clear space is 25% of shield height. At 34px that is ~9px, which the gap and
   the brand's own padding already exceed. */
.sidebar .brand__lockup { width: 145px; height: auto; }
.sidebar .brand__mark   { width: auto;  height: 34px; }

.sidebar .brand--cobranded { display: flex; align-items: center; gap: 11px; flex-wrap: nowrap; }
.sidebar .brand--cobranded .cp-brand__cobrand {
  display: flex; align-items: center; min-width: 0;
  padding-left: 11px; border-left: 1px solid rgba(244, 240, 231, .22);
}
.sidebar .brand--cobranded .cp-brand__cobrand img {
  height: 26px; width: auto; max-width: 118px; object-fit: contain;
}
/* The domain co-brand is real artwork in the domain's own colours and is
   never knocked out, inverted or plated — the PayChain MIS does not recolour a
   domain's mark any more than a domain recolours the PayChain MIS's. */
.sidebar .brand .cp-brand__cobrand img { filter: none; background: none; }
/* components.css stacks .finance-app .brand vertically for the two-line
   SmartSuite lockup. the PayChain MIS's is a mark plus a wordmark on one line. */
.finance-app .brand { flex-direction: row; align-items: center; flex-wrap: wrap; }

/* 4.1c  The sign-out row. The old shell's .bce-side__user is kept rather than
         rebuilt, because it already handles a long email without pushing the
         button off the edge. It just needs the template's dark-surface ink. */
.sidebar .bce-side__user {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 12px 7px 6px;
  border-top: 1px solid #1b3444;
  color: #b9c8d4;
}
.sidebar .bce-side__user-name {
  font-size: .8125rem;
  color: #fff;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sidebar .bce-side__user-role { font-size: .75rem; color: #7190a2; }
.sidebar .bce-priv {
  font: 700 .625rem/1 Manrope, sans-serif;
  background: #522b32;
  color: #ff9ba8;
  border-radius: 8px;
  padding: 2px 5px;
  margin-left: 4px;
}
.sidebar .icon-btn { border: 0; background: none; color: #9db0bd; }
.sidebar .icon-btn:hover { color: #fff; }
.sidebar .bc-avatar {
  width: 30px; height: 30px; flex: none;
  display: grid; place-items: center;
  border-radius: 9px;
  background: linear-gradient(145deg, #1ecaa9, #167be1);
  color: #fff;
  font: 700 .75rem Manrope, sans-serif;
}

/* 4.1d  Nav link colour.

   The template's .nav-item is a <button> in the demo and an <a> here, because
   these are real destinations and a button is not a link. That one change is
   enough for brookscorp.css's a{color:var(--bc-accent-600)} to reach it, and
   the sidebar comes up in sixteen blue links — accent everywhere, which breaks
   the rule the old shell was built on: the ACTIVE item is the only accent in
   the sidebar, and that is how you find where you are without reading.

   Restated at .sidebar .nav-item so it wins regardless of what the underlying
   sheets do to bare <a>. Same values finance.css uses. */
/* 4.1d-0  `.nav-item` IS TWO DIFFERENT COMPONENTS. This is the DevTools bug.

   finance.css:
     .nav-item{width:100%;display:flex;color:#9db0bd;padding:9px 10px;margin:2px 0;…}
   written for the sidebar — and applied to every .nav-item on the page.

   Bootstrap uses the SAME class name for tab and pill list items:
     <ul class="nav nav-tabs"><li class="nav-item"><button class="nav-link active">
   which is what DevTools' Response / Request / HMAC tab strip is built from.
   Each <li> therefore became width:100% and display:flex, so three tabs that
   should sit in a row stacked on top of each other inside a card header, in
   #9db0bd — pale blue-grey on white. That is the overlapping text Mike saw,
   and with the tab strip unusable the panes behind it never switch, which is
   the "data not rendering" half of the same report.

   The discriminator is the element: the PayChain MIS's sidebar items are <a>, and
   bootstrap's are <li>. So the sidebar rule keeps applying to <a class=
   "nav-item"> and every <li class="nav-item"> is handed back to bootstrap. */
li.nav-item {
  width: auto;
  display: list-item;
  padding: 0;
  margin: 0;
  color: inherit;
  background: none;
  border-radius: 0;
  text-align: inherit;
  font-size: inherit;
  gap: 0;
  transition: none;
}
li.nav-item:hover { background: none; color: inherit; }

/* Tabs, given the template's measurements. paychain.compat.css already draws
   .nav-tabs and .nav-link; this is the type scale and the accent rule. */
.nav-tabs { gap: 18px; border-bottom: 1px solid var(--bc-grey-200); }
.nav-tabs .nav-link {
  font: 600 .8125rem/1 Manrope, sans-serif;
  color: var(--bc-grey-500);
  padding: 10px 0;
  border: 0;
  background: none;
}
.nav-tabs .nav-link:hover { color: var(--bc-brand-600); background: none; }
.nav-tabs .nav-link.active {
  color: var(--bc-brand-600);
  background: none;
  box-shadow: inset 0 -2px var(--bc-accent-500);
}
/* .card-header-tabs sits the strip flush with the header's bottom edge. */
.card-header-tabs, .bc-card__head .nav-tabs { margin-bottom: -1px; }
/* A header carrying tabs keeps its rule — the tab underline needs something to
   sit against. §3.1 removes it from plain headers, which is right for those. */
.card-header:has(.nav-tabs), .bc-card__head:has(.nav-tabs) { padding-bottom: 0; border-bottom: 0; }

.sidebar .nav-item { color: #9db0bd; text-decoration: none; }
.sidebar .nav-item:hover { background: #112c3e; color: #fff; }
.sidebar .nav-item.active { color: #fff; }
.sidebar .nav-item .nav-icon { color: #72a0b8; }
.sidebar .nav-item.active .nav-icon { color: var(--brand-accent); }
.sidebar .suite-switch button, .sidebar .brand { color: #fff; text-decoration: none; }
.sidebar .control-card b { color: #fff; }

/* 4.1d-ii  Clickable KPI tiles.

   The template's .metrics article is inert. Three of the domain dashboard's
   five are destinations, and wrapping the article in an <a> is not an option:
   .metrics is a grid and the anchor would become the grid item, so the article
   would stop matching `.metrics article` and lose its entire skin. The
   stretched-link pattern keeps the article as the grid child and lets the
   whole tile be the hit area — with a real <a> carrying real text for anyone
   not using a mouse, rather than an onclick on a <div>. */
.metrics article.cp-metric--link { position: relative; }
.metrics article.cp-metric--link .cp-stretch { position: absolute; inset: 0; z-index: 1; }
.metrics article.cp-metric--link:hover { border-color: #aac8e3; }
.metrics article.cp-metric--link:focus-within { outline: 3px solid var(--brand-primary); outline-offset: 3px; }
/* Anything the reader must be able to select — a figure they will copy into a
   report — sits above the stretched link. */
.metrics article.cp-metric--link > strong { position: relative; z-index: 2; }

/* 4.1e  The dark KPI tile.

   .metrics .dark-metric is the one white-on-dark card in the template and it
   sets color:#fff on the article. Its value is a <strong>, and in the MIS that
   <strong> also carries .bc-money — which BCDF paints --bc-grey-700 for
   contrast on white. On the dark tile that is near-black on near-black: the
   headline figure vanishes. Money inside a dark surface inherits. */
.dark-metric strong, .dark-metric .bc-money,
.treasury-panel .bc-money, .drawer-stat .bc-money { color: inherit; }

/* 4.1f  Powered-by. The ITCognify mark, as the template has it. The sidebar is
         a dark surface and the artwork is dark-on-transparent, so it needs the
         white plate components.css already gives .sidebar .brand img — which
         4.1b switched OFF for the the PayChain MIS knockout mark. Only the vendor mark
         gets the plate; the two are different problems on the same surface. */
.sidebar .powered-by { padding: 10px 8px 4px; }
.sidebar .powered-by small { display: block; font: 700 .625rem/1 Manrope, sans-serif; letter-spacing: .14em; color: #577284; margin-bottom: 6px; }
.sidebar .powered-by img { width: 120px; height: auto; background: #fff; padding: 5px 7px; border-radius: 6px; }
.page > footer .footer-powered { color: #87939c; display: inline-flex; align-items: center; gap: 6px; }
.page > footer .footer-powered img { width: 92px; height: auto; }

/* 4.2  Twenty-one items at the template's 9px padding overflows a 900px
        laptop even with the scroll above; tighten the rhythm rather than
        hiding groups, because hiding is what the role gates already do. */
.sidebar nav p { margin: 14px 11px 6px; }
.sidebar .nav-item { padding: 7px 10px; margin: 1px 0; }

/* 4.3  The top bar carries the domain and school switchers, which are real
        controls with text, not 38px glyphs. Let it wrap rather than push the
        avatar off the edge. */
.topbar { flex-wrap: wrap; row-gap: 8px; padding-block: 10px; }
.top-actions { flex-wrap: wrap; justify-content: flex-end; }
.top-actions .bce-chip, .top-actions form, .top-actions .cp-user { display: flex; align-items: center; }

/* The financial-year block. In the template it is a <button> with a chevron,
   and .period{display:grid;grid-template-columns:auto 12px} puts the label and
   the year in column one and the chevron in column two. Here it is a static
   <span> with no chevron, so the grid leaves an empty 12px track and squeezes
   "2026 / 27" into a narrow column that breaks across three lines and collides
   with the label above it. Two rows, no columns, and the year does not wrap. */
.topbar .period {
  display: block;
  padding-right: 16px;
  white-space: nowrap;
  width: auto;
}
.topbar .period small { display: block; }
.topbar .period b { display: block; font-size: .875rem; }

/* 4.4  The template's .page-head renders ViewData Title/Description. the MIS
        views render _PageHeader themselves with a breadcrumb and their own
        actions, so the two would stack. _Layout emits .page-head ONLY when
        the view has not supplied one (ViewData["OwnHeader"]), and this is the
        spacing for the case where the view supplies it. */
.page > .bce-page:first-child { padding-top: 0; }
.bce-crumbs { font-size: .75rem; color: #71808d; margin-bottom: 8px; }

/* Three header partials grew up here at different times — _PageHeader (BCDF),
   _PageHead (MIS v2) and _InstitutionPageHeader (institution module) — and 44
   of the 49 views skip all three and write the heading inline, almost always
   as `<div class="d-flex justify-content-between"><h4 class="fw-bold">`.
   That is four idioms for one object. They are not being rewritten here, but
   they are given ONE set of measurements, so a person moving between screens
   sees the title in the same place at the same size every time. The inline h4
   keeps its own size: it was never a page title in the markup, and inflating
   every h4 in the MIS would also inflate the card titles. */
.bce-pagehead, .cp-pagehead { margin-bottom: 23px; align-items: flex-end; }
.bce-pagehead__title h1, .cp-pagehead h1, .bc-pagehead__title {
  font: 700 1.75rem/1.15 Manrope, sans-serif;
  letter-spacing: -.035em;
  margin: 0;
}
.bce-pagehead__sub, .bc-pagehead__sub { color: var(--bc-grey-500); font-size: .875rem; margin: 6px 0 0; }
.bce-pagehead__actions, .cp-pagehead__actions { display: flex; gap: 9px; flex-wrap: wrap; }

/* 4.5  The environment band and chip survive the reskin unchanged in meaning
        — a clerk must never wonder whether they are in UAT — but they now sit
        against the template's topbar rather than BCDF's. */
.bce-envband { height: 3px; }
.bce-env { font: 700 .75rem/1 Manrope, sans-serif; border-radius: 9px; padding: 4px 8px; }


/* ==========================================================================
   5 · DARK MODE
   ==========================================================================
   The SmartSuite template has no dark mode — it is a light design with dark
   panels. The user menu still offers a Light/dark toggle (CP.theme.toggle),
   and BCDF's dark block would repaint the template's white panels without
   touching any of the template's own rules, producing white text on white.
   Until a dark variant of the template exists, the toggle is neutralised
   here rather than left to half-work.
   ========================================================================== */
[data-theme="dark"] .page,
[data-theme="dark"] .panel,
[data-theme="dark"] .bc-card,
[data-theme="dark"] .card { background: #fff; color: var(--bc-brand-600); }

/* ==========================================================================
   6 · THE PUBLIC SUPPLIER REGISTRATION FORM
   ==========================================================================
   The one anonymous screen in the MIS. It uses _BlankLayout, so none of the
   shell rules above apply and it needs its own measurements — a single column
   at a readable width, generous space BETWEEN card groups and tight space
   within them, because a supplier is filling this in on a phone and every
   ambiguous gap is a chance to lose them.
   ========================================================================== */
.cp-register {
  max-width: 720px;
  margin: 0 auto;
  padding: 32px 16px 64px;
}
.cp-register--narrow { max-width: 560px; }

.cp-register__head { margin-bottom: 22px; }
.cp-register__head h1 { font: 700 1.75rem/1.15 Manrope, sans-serif; letter-spacing: -.035em; margin: 0; }
.cp-register__label { font-weight: 600; color: var(--bc-brand-600); margin: 6px 0 0; }
.cp-register__intro { color: var(--bc-grey-500); margin: 8px 0 0; }

/* Cards are the groups. The gap between them is what makes the form read as
   three short forms rather than one long one. */
.cp-register .bc-card { margin-bottom: 20px; }
.cp-register .bc-card__head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.cp-register .bc-card__head h2 { font: 700 1rem/1.2 Manrope, sans-serif; margin: 0; }

/* One column, always. Two columns of fields at 390px is how a form is abandoned
   halfway — and this form has no "save and come back". */
.cp-register__fields { display: grid; gap: 16px; }
.cp-register__fields .bc-field { display: grid; gap: 6px; margin: 0; }
.cp-register__fields .bc-input,
.cp-register__fields .bc-select { width: 100%; }
.cp-register__fields textarea.bc-input { height: auto; padding: 10px 12px; line-height: 1.5; }

.cp-register__submit { margin-top: 26px; display: grid; gap: 10px; justify-items: start; }
.cp-register__submit .bc-btn { min-width: 220px; }

.cp-register__steps { margin: 8px 0 18px; padding-left: 20px; display: grid; gap: 8px; color: var(--bc-grey-700); }

@media (max-width: 520px) {
  .cp-register { padding: 20px 14px 48px; }
  .cp-register__head h1 { font-size: 1.4375rem; }
  .cp-register__submit .bc-btn { min-width: 0; width: 100%; }
}


/* ==========================================================================
   7.  DETAIL PAGES
   --------------------------------------------------------------------------
   A detail page is a page whose job is to state facts about one record. There
   are ten of them and they were all drifting apart, so the treatment lives
   here — on the markup those pages ALREADY use — rather than in each view.

   7.1  The missing Reboot rule.

   THE BUG BEHIND "everything is so scattered". `bootstrap-compat.css` is a
   hand-written subset of Bootstrap and it reimplements the grid, but not
   Reboot. Reboot contains `dd { margin-left: 0 }`. Without it the UA default
   of 40px survives, so a `<dl class="row">` whose `dt.col-sm-5` and
   `dd.col-sm-7` add up to exactly 100% adds up to 100% + 40px instead — and
   the flex row wraps. Every value dropped onto its own line, indented 40px
   under its own label. Measured on School/Details: dt 222px + dd 310px = 532px
   into a 532px track, plus 40px of margin.

   One line repairs all fourteen definition lists in the app. It is written
   against `dd` alone, exactly as Reboot has it, because the omission is
   Reboot's, not this page's. */
dd { margin-inline-start: 0; }

/* --------------------------------------------------------------------------
   7.2  The specification list.

   With the wrap fixed the rows align, but a bare grid of 12 facts still reads
   as a wall. What separates the groups here is the hairline, not the gap: the
   rows sit close, the rule between them does the work a blank half-line was
   doing badly, and the space that IS left is between the cards.

   Grid rather than flex, because a two-track grid can size the label column
   off the longest label instead of a hardcoded 41.67% that leaves a canyon
   next to "Phase". */
.card-body > dl.row,
.card-body > dl.bc-dl {
  display: grid;
  grid-template-columns: minmax(116px, 34%) 1fr;
  column-gap: 0;          /* the gap is padding INSIDE the label cell, so the
                             hairline under a row runs unbroken across both
                             columns instead of stopping at a 18px gutter */
  row-gap: 0;
  align-items: baseline;  /* label and value share a baseline even though the
                             label is 13px and the value 14px, and a badge sits
                             on it rather than floating above it */
  margin: 0;
}

/* The grid children are `dt`/`dd` carrying col-sm-* classes from before. Those
   set width, the .row rule sets gutter padding, and the UA sets dd margin —
   all three are wrong inside a grid track, and all three are reset here rather
   than stripped from ten views by hand. `dl.row > dt` is 0-1-2 against
   `.col-sm-5`'s 0-1-0, so none of this needs !important. */
.card-body > dl.row > dt,
.card-body > dl.row > dd {
  width: auto;
  max-width: none;
  flex: none;
  margin: 0;
  padding: 8px 0;
  border-top: 1px solid var(--bc-border, #e7edf1);
  min-width: 0;
}

/* The first pair opens the list; a rule above the first row would read as the
   bottom of the card header. */
.card-body > dl.row > dt:first-of-type,
.card-body > dl.row > dt:first-of-type + dd { border-top: 0; padding-top: 0; }

.card-body > dl.row > dt {
  font-size: .8125rem;
  font-weight: 500;
  line-height: 1.45;
  color: var(--bc-text-muted, #6f7e8c);
  padding-right: 18px;
}

.card-body > dl.row > dd {
  font-size: .875rem;
  font-weight: 500;
  line-height: 1.45;
  color: var(--bc-text-body, #1e2b36);
  overflow-wrap: anywhere;
}

/* A badge is a block of colour on a 30px row; it should not also carry the
   row's line-height. */
.card-body > dl.row > dd > .badge { vertical-align: baseline; }

/* At phone width a 116px label column against a long value is two words per
   line. Below 560px the list stacks — but tightly, and the hairline moves to
   the label so a pair still reads as a pair. */
@media (max-width: 559.98px) {
  .card-body > dl.row { grid-template-columns: 1fr; }
  .card-body > dl.row > dt { padding: 8px 18px 0 0; }
  .card-body > dl.row > dd { padding: 1px 0 8px; border-top: 0; }
  .card-body > dl.row > dt:first-of-type + dd { padding-top: 1px; }
}

/* --------------------------------------------------------------------------
   7.3  The figure list.

   The financial column of a detail page is four figures, each with an icon
   tile. It was built as four `.d-flex` rows with 48px avatars and a 16px
   margin under each — 64px of page per number, and no line between them, so
   four unrelated figures floated in one field of white.

   Same rhythm as the spec list above: one hairline per row, tile down to 36px,
   figure in Manrope so it matches every other number in the template. */
.cp-figures { display: grid; }

.cp-figure {
  display: grid;
  grid-template-columns: 36px 1fr;
  column-gap: 13px;
  align-items: center;
  padding: 11px 0;
  border-top: 1px solid var(--bc-border, #e7edf1);
}
.cp-figure:first-child { border-top: 0; padding-top: 2px; }
.cp-figure:last-child  { padding-bottom: 2px; }

.cp-figure__icon {
  width: 36px; height: 36px;
  border-radius: 10px;
  display: grid; place-items: center;
  font-size: 18px;
  line-height: 1;
}

.cp-figure__body { min-width: 0; }

.cp-figure__label {
  display: block;
  font-size: .75rem;
  line-height: 1.35;
  color: var(--bc-text-muted, #6f7e8c);
}

/* Manrope, and the money compensation switched OFF — this is a `font:`
   shorthand, so it resets font-family away from IBM Plex Mono and the -.22em
   word-spacing that closes en-ZA's group separator would pull the digits into
   each other. Same trap as the dashboard metrics. */
.cp-figure__value {
  display: block;
  font: 700 1.0625rem/1.25 Manrope, sans-serif;
  letter-spacing: -.02em;
  word-spacing: normal;
  margin-top: 2px;
}
.cp-figure__value.is-spent { color: #C94455; }

.cp-figure__note {
  display: block;
  font-size: .6875rem;
  line-height: 1.4;
  color: var(--bc-text-muted, #6f7e8c);
  margin-top: 2px;
}

/* The utilisation bar closes the card, so it gets the same hairline the rows
   above it use rather than a free-floating margin. */
.cp-figures + .cp-utilisation {
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--bc-border, #e7edf1);
}
.cp-utilisation__head {
  display: flex; justify-content: space-between; align-items: baseline;
  font-size: .75rem; margin-bottom: 6px;
}
.cp-utilisation__head b { font: 700 .75rem Manrope, sans-serif; }

/* --------------------------------------------------------------------------
   7.4  Inline notices inside a detail card.

   The manual-budget and no-allocation notices sit between figures. At the
   alert's normal size they outweigh the numbers they are annotating. */
.card-body > .alert.cp-note {
  /* A notice inside a detail card is one sentence, not a structured alert.
     The base .alert is a flex row, which turns "<strong>label:</strong> text"
     into two competing columns — the label wrapped over three lines in a
     column of its own. Block puts the sentence back. */
  display: block;
  padding: 9px 11px;
  margin: 10px 0;
  font-size: .75rem;
  line-height: 1.5;
  border-radius: 10px;
}
.card-body > .alert.cp-note > i { margin-right: 4px; }


/* ==========================================================================
   8.  TABLES AND THEIR TOOLBARS
   --------------------------------------------------------------------------
   8.1  The toolbar sitting ON the table.

   `.card-header` carries `padding: 19px 19px 0` (§3.1) — no bottom padding,
   because the `.card-body` underneath supplies the missing 19px and a doubled
   gutter would look like a gap.

   When a TABLE follows the header instead of a body, nothing supplies it. The
   toolbar's button ends up resting directly on the table's header row, which
   is what Mike flagged on Chart of Accounts: roughly 3px between the bottom of
   "Add Account" and the top of the ACC # row. 28 tables across 23 views are
   built this way, so it is the rule that is wrong, not the view.

   `:has()` rather than a class on 23 views — and the sheet already relies on it
   two rules up for `.card-header:has(.nav-tabs)`. */
.card-header:has(+ .table-responsive),
.card-header:has(+ .bc-table-wrap),
.card-header:has(+ table),
.bc-card__head:has(+ .table-responsive),
.bc-card__head:has(+ .bc-table-wrap),
.bc-card__head:has(+ table) {
  padding-bottom: 15px;
}

/* The toolbar row itself. A count on the left and one or two actions on the
   right is the shape in every one of those 23 views, so it is stated once:
   centred on one line, a real gap between adjacent buttons, and wrapping
   rather than crushing when the viewport is narrow. min-height keeps a header
   holding a 30px .btn-sm the same height as one holding a 34px button, so a
   column of cards does not step. */
.card-header.d-flex,
.bc-card__head {
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  min-height: 34px;
}
.card-header > .d-flex,
.bc-card__head > .d-flex { gap: 8px; flex-wrap: wrap; }

/* --------------------------------------------------------------------------
   8.2  The table's outer gutter.

   `td { padding: 10px 8px }` comes from the template, where the table is a
   bare grid on the page background and 8px is the right column rhythm. Inside
   a bordered card it is not: the first column starts 8px from the card edge
   while the toolbar above it starts at 19px, so the header and the table it
   belongs to are visibly out of line — "25 account(s)" at 19px sitting over
   "ACC #" at 8px.

   The between-column rhythm stays at 8px; only the two outer cells take the
   card's gutter, which is what sets a table INTO a card rather than on top of
   one. Applied at the row level so thead, tbody and tfoot all agree. */
.card > .table-responsive > .table > * > tr > :first-child,
.card > .bc-table-wrap > .table > * > tr > :first-child,
.card > .table > * > tr > :first-child,
.bc-card > .table-responsive > .table > * > tr > :first-child,
.bc-card > .bc-table-wrap > .bc-table > * > tr > :first-child {
  padding-left: 19px;
}
.card > .table-responsive > .table > * > tr > :last-child,
.card > .bc-table-wrap > .table > * > tr > :last-child,
.card > .table > * > tr > :last-child,
.bc-card > .table-responsive > .table > * > tr > :last-child,
.bc-card > .bc-table-wrap > .bc-table > * > tr > :last-child {
  padding-right: 19px;
}

/* --------------------------------------------------------------------------
   8.3  Row actions.

   The last column of a data table is nearly always two or three small buttons.
   Left to inline-block they inherit whatever whitespace the Razor happened to
   emit — sometimes a 4px text space, sometimes none where a tag hugged the
   next. A flex row gives every table in the app the same gap, and `justify`
   follows the `.text-end` the views already put on the header cell. */
.table td .bc-row,
.table td > .btn + .btn,
.table td > .bc-btn + .bc-btn { margin-left: 0; }

.table tbody td.cp-actions,
.table tbody td.text-end:has(> .btn, > .bc-btn, > form) {
  white-space: nowrap;
}
.table tbody td.text-end > .btn,
.table tbody td.text-end > .bc-btn,
.table tbody td.text-end > form {
  vertical-align: middle;
}
.table tbody td.text-end > .btn + .btn,
.table tbody td.text-end > .bc-btn + .bc-btn,
.table tbody td.text-end > .btn + form,
.table tbody td.text-end > form + .btn,
.table tbody td.text-end > form + form { margin-left: 6px; }

/* --------------------------------------------------------------------------
   8.4  The table's last row against the card edge.

   A table that ends the card gets no bottom padding from anything, so the last
   row's text sits on the card's 1px border. `mb-0` on the table (which every
   one of these views sets, to stop a stray bootstrap margin breaking the
   radius) is what removes it, so the room has to come from the cell. */
.card > .table-responsive:last-child .table > tbody > tr:last-child > td,
.card > .bc-table-wrap:last-child .table > tbody > tr:last-child > td,
.card > .table:last-child > tbody > tr:last-child > td {
  padding-bottom: 13px;
}


/* ==========================================================================
   9.  FILE UPLOAD
   --------------------------------------------------------------------------
   The institution logo picker. A bare `<input type="file">` renders as the
   browser's own grey button plus "No file chosen" — a control that looks
   nothing like the rest of this form and gives no preview, which for a logo is
   the one thing that matters: people need to see that they picked the right
   crest before they commit a domain to it.

   So the input is taken out of the layout and a label is styled in its place.
   The label, not a div with a click handler: clicking a label for a file input
   opens the picker natively, which means keyboard focus, Enter and Space all
   behave without a line of script. If paychain.upload.js never loads, this
   still opens a file browser and still posts the file — it just loses the
   thumbnail. */
.cp-upload { display: grid; gap: 10px; }

/* Not display:none — a hidden input cannot be focused, and screen readers skip
   it. Clipped instead, so it stays in the tab order and the label's focus ring
   has something to attach to. */
.cp-upload__input {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.cp-upload__zone {
  display: grid;
  grid-template-columns: 44px 1fr auto;
  align-items: center;
  gap: 14px;
  padding: 16px;
  border: 1px dashed var(--bc-grey-300, #ccd7de);
  border-radius: 12px;
  background: var(--bc-grey-50, #f7f9fa);
  cursor: pointer;
  transition: border-color .15s, background .15s;
}
.cp-upload__zone:hover { border-color: var(--bc-accent-400, #6aa6f8); background: #fff; }

/* The focus ring belongs on the zone even though the focus is on the input
   next to it — :focus-visible on the input, ring on the thing you can see. */
.cp-upload__input:focus-visible + .cp-upload__zone {
  outline: 2px solid var(--bc-accent-500, #2579f5);
  outline-offset: 2px;
  border-color: transparent;
}

.cp-upload.is-over .cp-upload__zone {
  border-color: var(--bc-accent-500, #2579f5);
  border-style: solid;
  background: var(--bc-accent-50, #eef4ff);
}
.cp-upload.is-invalid .cp-upload__zone { border-color: var(--bc-danger-fg, #c94455); }

/* Once a file is chosen the zone stops being the headline — the preview is.
   It stays visible and clickable so "wrong one, pick again" is one click. */
.cp-upload.has-file .cp-upload__zone {
  padding: 10px 14px;
  border-style: solid;
  background: #fff;
}
.cp-upload.has-file .cp-upload__icon { display: none; }
.cp-upload.has-file .cp-upload__zone { grid-template-columns: 1fr auto; }

.cp-upload__icon {
  width: 44px; height: 44px;
  border-radius: 12px;
  display: grid; place-items: center;
  background: var(--bc-accent-50, #eef4ff);
  color: var(--bc-accent-600, #1c62d6);
  font-size: 22px;
}

.cp-upload__copy { min-width: 0; display: grid; gap: 2px; }
.cp-upload__copy strong { font: 600 .875rem/1.3 Manrope, sans-serif; }
.cp-upload__copy small  { font-size: .75rem; color: var(--bc-text-muted, #6f7e8c); }

/* A span, not a button — a button inside a label swallows the click on some
   browsers and the label is what opens the picker. It is styled as one and
   marked aria-hidden so it is not announced as an interactive control. */
.cp-upload__browse { pointer-events: none; }

/* ── The chosen file ──────────────────────────────────────────────────────── */
.cp-upload__picked {
  display: grid;
  grid-template-columns: 52px 1fr auto;
  align-items: center;
  gap: 13px;
  padding: 10px 12px;
  border: 1px solid var(--bc-grey-200, #e7edf1);
  border-radius: 12px;
  background: #fff;
}

/* contain, not cover: a logo cropped to fill a square is a logo with its edges
   cut off, which is precisely the thing the preview exists to let you catch.
   The chequerboard shows transparency, so a white-on-transparent mark does not
   look like an empty box. */
.cp-upload__thumb {
  width: 52px; height: 52px;
  object-fit: contain;
  border-radius: 8px;
  background-color: #fff;
  background-image:
    linear-gradient(45deg, #eef2f5 25%, transparent 25%, transparent 75%, #eef2f5 75%),
    linear-gradient(45deg, #eef2f5 25%, transparent 25%, transparent 75%, #eef2f5 75%);
  background-size: 12px 12px;
  background-position: 0 0, 6px 6px;
  border: 1px solid var(--bc-grey-200, #e7edf1);
}

/* `hidden` has to be restated against every rule here that sets display, because
   the UA's `[hidden] { display: none }` is a single attribute selector and loses
   to an author class of equal specificity. Without this the empty preview box
   renders as a stray pill under the drop zone before any file is chosen. */
.cp-upload__picked[hidden],
.cp-upload__error[hidden] { display: none; }

.cp-upload__meta { min-width: 0; display: grid; gap: 2px; }
.cp-upload__meta strong {
  font-size: .8125rem; font-weight: 600;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cp-upload__meta small { font-size: .75rem; color: var(--bc-text-muted, #6f7e8c); }

.cp-upload__error { margin: 0; font-size: .8125rem; }

.cp-upload__warn { display: block; margin-top: 4px; color: var(--bc-warning-fg, #ad6c1a); }

/* ── The "already hosted" escape hatch ────────────────────────────────────── */
/* Collapsed by default: it is the exception, and an open URL field next to an
   upload box invites people to fill in both. */
.cp-upload__alt { margin-top: 4px; }
.cp-upload__alt > summary {
  cursor: pointer;
  font-size: .8125rem;
  color: var(--bc-accent-600, #1c62d6);
  padding: 4px 0;
  width: max-content;
}
.cp-upload__alt > summary:hover { text-decoration: underline; }
.cp-upload__alt[open] > summary { margin-bottom: 10px; }

@media (max-width: 560px) {
  .cp-upload__zone { grid-template-columns: 1fr; text-align: center; justify-items: center; }
  .cp-upload.has-file .cp-upload__zone { grid-template-columns: 1fr; }
  .cp-upload__picked { grid-template-columns: 52px 1fr; }
  .cp-upload__picked > .bc-btn { grid-column: 1 / -1; justify-self: start; }
}

/* ==========================================================================
   10.  CARD CORNERS
   --------------------------------------------------------------------------
   A tinted card header (`.card-header.bg-label-*` over `.card.border-*`, as on
   EMIS Sync) showed its own corner arc crossing the card's border arc, so the
   two lines did not meet at the top corners.

   The cause is two different radius tokens describing the same box. §3.1 sets
   the card itself to `--bc-radius-lg` (14px) as part of the SmartSuite template.
   `paychain.compat.css` rounds the first and last child by
   `calc(var(--bc-r-card) - 1px)`, and `--bc-r-card` is a BCDF token still
   resolving to 16px — so the header was drawn at 15px inside a 14px card and
   bulged past it by a pixel at each corner. Invisible on a white header;
   obvious the moment the header carries a tint and the card a coloured border.

   The inner radius has to be the outer radius MINUS the border width, or the
   child's arc and the border's arc are concentric-but-offset, which is the same
   artefact one pixel the other way. `overflow: hidden` on `.card` would also
   hide it, and would clip every dropdown opened from inside a card header, so
   the radii are corrected instead. */
.card > :first-child,
.bc-card > :first-child,
.bce-card > :first-child {
  border-top-left-radius:  calc(var(--bc-radius-lg) - 1px);
  border-top-right-radius: calc(var(--bc-radius-lg) - 1px);
}
.card > :last-child,
.bc-card > :last-child,
.bce-card > :last-child {
  border-bottom-left-radius:  calc(var(--bc-radius-lg) - 1px);
  border-bottom-right-radius: calc(var(--bc-radius-lg) - 1px);
}

/* A single child is both the first and the last, so it takes all four. */
.card > :only-child,
.bc-card > :only-child,
.bce-card > :only-child { border-radius: calc(var(--bc-radius-lg) - 1px); }


/* ==========================================================================
   11.  COUNT CHIPS
   --------------------------------------------------------------------------
   `.bc-pill` is a FILTER CHIP. Its `flex: 1 1 0` gives every chip in a row an
   identical share of the width no matter what is in it, which is right for a
   row of toggles — "All / Active / Closed" look deliberate when they match —
   and it is what BudgetCategory uses them for.

   DevTools borrows the same class for label + number pairs, and there the
   equal-width rule is wrong in a way that shows: a basis of 0 means the box is
   sized by the row, not the content, so "SchoolAllocationDetails 24 060" gets
   the same 74px as "Schools 120". With `white-space: nowrap` and centred
   content and no clipping, the text then spills out of BOTH sides of its own
   chip and lands on its neighbours. Measured on the real markup: 10 of 13 chips
   had text outside their own box.

   A variant rather than a change to `.bc-pill`, because the equal widths are
   deliberate where that class is used as intended. */
.bc-pill--count {
  flex: 0 1 auto;            /* size to content — this line IS the fix */
  justify-content: flex-start;
  gap: 7px;
  height: auto;
  min-height: 30px;
  min-width: 0;
  padding: 5px 10px;
  font-size: .75rem;
  cursor: default;
}

/* It is a readout, not a control: no hover affordance. */
.bc-pill--count:hover {
  border-color: var(--bc-border-strong);
  color: var(--bc-text-body);
}

.bc-pill--count > .bc-money { font-weight: 700; }


/* ==========================================================================
   12.  COLOUR FIELD
   --------------------------------------------------------------------------
   Every screen that captures branding had a hex box, and three of the four had
   no way to see the colour it named. The one that did — Domain Edit — wired
   the native picker ONE WAY: picking a colour filled the text box, but typing
   or pasting a hex changed nothing on screen. Since these values arrive pasted
   out of a brand guide far more often than they are picked, the direction that
   was missing is the one that mattered: you could type #1A4F8A, save, provision
   a PayChain domain with it, and never once see the colour.

   The swatch is a <label> wrapping a real <input type="color">, not a div with
   a click handler. That is what makes it work with no script and keeps keyboard
   focus on an actual control. The input is clipped rather than
   `display: none`, because a hidden input is not focusable and some browsers
   will not open the picker for one.
   ========================================================================== */

.cp-colour__row {
  display: grid;
  grid-template-columns: 40px 1fr;
  align-items: stretch;
  gap: 8px;
}

.cp-colour__swatch {
  position: relative;
  overflow: hidden;                    /* clips the native control's own chrome */
  display: block;
  min-height: 40px;
  border: 1px solid var(--bc-grey-300, #d6dfe6);
  border-radius: 10px;
  cursor: pointer;

  /* A chequerboard UNDER the colour, so a swatch showing a pale or unset value
     still reads as a swatch and not as a gap in the form. The colour itself is
     painted as an inline background by the server and then by the script, which
     covers this entirely whenever a colour is actually set. */
  background-color: #fff;
  background-image:
    linear-gradient(45deg, #eef2f5 25%, transparent 25%, transparent 75%, #eef2f5 75%),
    linear-gradient(45deg, #eef2f5 25%, transparent 25%, transparent 75%, #eef2f5 75%);
  background-size: 10px 10px;
  background-position: 0 0, 5px 5px;

  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .6);   /* separates a dark swatch from its border */
  transition: box-shadow .15s ease, border-color .15s ease;
}

.cp-colour__swatch:hover { border-color: var(--bc-border-strong, #b9c6d1); }

/* Clipped, not hidden — see the section note. 1px at the corner keeps it inside
   the label's box so the picker pops up anchored to the swatch. */
.cp-colour__picker {
  position: absolute;
  left: 0; top: 0;
  width: 1px; height: 1px;
  padding: 0; margin: 0; border: 0;
  opacity: 0;
}

/* The focus ring belongs on the swatch, which is the part the user can see —
   the input it wraps is one clipped pixel. */
.cp-colour__swatch:focus-within {
  box-shadow: 0 0 0 3px var(--bc-accent-100, #d8e6fd);
  border-color: var(--bc-accent-400, #6aa6f8);
}

/* Hex is a code, not prose: tabular figures stop the box jittering as the
   characters change, and upper case matches how brand guides write them. */
.cp-colour__hex {
  font-family: var(--bc-font-mono, ui-monospace, "Cascadia Mono", Menlo, Consolas, monospace);
  font-size: .8125rem;
  letter-spacing: .02em;
  text-transform: uppercase;
}

/* A visually-hidden utility of our own. `.visually-hidden` exists, but only in
   bootstrap-compat.css, and these partials render on screens that do not all
   load it. */
.cp-sr {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}


/* ==========================================================================
   9.1  THE LOGO ALREADY ON THE RECORD
   --------------------------------------------------------------------------
   §9 built the uploader for a CREATE screen, where there is nothing to show
   until a file is picked. On an edit screen there usually is a logo already,
   and a screen that shows only an empty drop zone reads as "there is no logo" —
   which is how somebody ends up uploading a second copy of the one that is
   already there. Same thumbnail treatment as the preview so the two are
   obviously the same kind of thing: the outgoing image and the incoming one.
   ========================================================================== */

.cp-upload__current {
  display: grid;
  grid-template-columns: 52px 1fr;
  align-items: center;
  gap: 13px;
  padding: 10px 12px;
  border: 1px solid var(--bc-grey-200, #e7edf1);
  border-radius: 12px;
  background: var(--bc-grey-50, #f7f9fb);
}

/* Once a replacement has been chosen, the outgoing logo is noise — the preview
   below it is now the answer to "what will this be". */
.cp-upload.has-file .cp-upload__current { display: none; }

/* A broken src (a logo whose blob was deleted, or a local URL from another
   environment) would otherwise render as the browser's torn-image glyph inside
   an otherwise tidy card. It still occupies the slot, so the layout holds. */
.cp-upload__current .cp-upload__thumb { display: block; }

@media (max-width: 560px) {
  .cp-upload__current { grid-template-columns: 44px 1fr; gap: 10px; }
}


/* ==========================================================================
   13.  CREDENTIAL PANEL — ROW LAYOUT
   --------------------------------------------------------------------------
   `.cp-cred__grid` is a wrapping FLEX row, which is right for the wallet
   hand-off it was built for: two short pairs, Username and Temporary password,
   sitting side by side.

   The demo-seed panel puts three pairs in it, each with a sentence of
   explanation under the value, and a flex row turns that into a ragged
   staircase — the explanation for one account ends up alongside the email of
   the next. Same component, a different shape of content, so a modifier rather
   than a change to the original.
   ========================================================================== */

.cp-cred__grid--rows {
  display: grid;
  grid-template-columns: max-content 1fr;
  align-items: baseline;
  gap: 8px 18px;
}

/* The flex version sets a right margin on every dd to space the pairs out
   horizontally. In a grid that margin is a gap the grid has already provided,
   and it pushes the last column short of the panel edge. */
.cp-cred__grid--rows dd { margin: 0; }

/* The description under a value is secondary to it — same size as the note it
   borrows the class from, but it needs the line to ITSELF. `.cp-cred__note` is
   inline where it came from (it sits beside a button), and inline here means the
   sentence starts alongside the password and wraps back under the LABEL column,
   so "approve suppliers." reads as though it belongs to the next role. */
.cp-cred__grid--rows .cp-cred__note {
  display: block;
  margin-top: 3px;
  line-height: 1.45;
}

/* Role names are camel case and read as words — InstitutionAdmin, SupplierUser.
   The base dt rule upper-cases its labels, which is right for "USERNAME" and
   turns these into INSTITUTIONADMIN. */
.cp-cred__grid--rows dt {
  text-transform: none;
  font-size: .8125rem;
  letter-spacing: 0;
}

@media (max-width: 560px) {
  /* Below this the label column steals too much from the value, and an email
     address is the thing that must stay readable. */
  .cp-cred__grid--rows { grid-template-columns: 1fr; gap: 2px; }
  .cp-cred__grid--rows dt { margin-top: 10px; }
}


/* ==========================================================================
   7 · WARM NEUTRALS ON THE DARK CHROME — LAST, ON PURPOSE
   ==========================================================================
   This block has to sit at the END of the file.

   Section 4 sets the sidebar's own type colours (.sidebar .nav-item and
   friends) at the same specificity as these rules. Written up in section 1b
   where they logically belong, they lost on source order and the sidebar stayed
   blue — which is exactly what it looked like: correct, and quietly wrong.
   Raising specificity instead would have worked and would have left the next
   person to fight it. Order is the honest fix.
   ========================================================================== */

/* The template's TYPE colours on those dark surfaces are the same problem one
   layer down: #9db0bd, #577284, #72a0b8, #7190a2, #7990a0, #668092 — all mixed
   against a navy chrome, all of them visibly COLD blue-grey sitting on Obsidian
   next to a warm ivory page. Nothing was broken; it just did not look like the
   same brand as the rest of the screen.

   These are the CI's Stone family instead, each step chosen so it still clears
   4.5:1 on Obsidian. Verified: #B8B1A6 12.0:1, #9A9389 8.5:1, #8A8379 7.0:1. */
.sidebar .nav-item          { color: #B8B1A6; }
.sidebar nav p              { color: #8A8379; }      /* group headings */
.sidebar .nav-item .nav-icon { color: #9A9389; }
.sidebar .nav-item.active .nav-icon,
.sidebar .nav-item.active   { color: var(--brand-canvas); }
.sidebar .nav-item.active .nav-icon { color: var(--brand-accent); }
.sidebar .nav-item:hover    { color: var(--brand-canvas); }

.sidebar .suite-switch > small { color: #8A8379; }
.sidebar .suite-switch em      { color: #9A9389; }
.sidebar .suite-switch b       { color: var(--brand-canvas); }

.sidebar .control-card small { color: #9A9389; }
.sidebar .control-card b     { color: var(--brand-canvas); }
.sidebar .control-card svg   { color: var(--brand-accent); }

.sidebar .bce-side__user-name { color: var(--brand-canvas); }
.sidebar .bce-side__user-role { color: #9A9389; }
.sidebar .bce-side__links a   { color: #9A9389; }
.sidebar .bce-side__links a:hover { color: var(--brand-canvas); }

/* Dark panels in the page body carry the same cold greys. */
.treasury-panel .treasury-stats small,
.budget-hero p:not(.eyebrow),
.bank-strip small { color: #9A9389; }
.treasury-stats div, .bank-strip > div { border-color: #2E2B26; }
