/* ═══════════════════════════════════════════════════════════════════════════
   NobleNeo v2 design tokens — extracted from sidebar-prototype.html
   ═══════════════════════════════════════════════════════════════════════════
   Import once in root.jsx (or via app.css) BEFORE any v2/new/ component is
   rendered. All classes here are prefixed `nv2-` to avoid clashing with the
   existing legacy `v2-` classes from `app/components/v2/index.jsx`.

   - Colour ramps  : --nv2-bg, --nv2-ink, --nv2-brand, --nv2-accent, etc.
   - Hub accents   : set --nv2-hub-accent on a parent to colour buttons,
                     active states, focus rings, gradients per-hub.
   - Typography    : Sora (display) + Manrope (body) loaded via Google Fonts
                     in tokens.css's @import or in root.jsx.
   - Shadows       : 5-step shadow scale.
   - Radius        : --nv2-radius-sm/md/lg.
   - Animations    : @keyframes fadeIn, slideDown, toastIn, pulse, hubFade.
   ═══════════════════════════════════════════════════════════════════════ */

@import url('https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&family=Sora:wght@500;600;700;800&display=swap');

:root {
  /* ── Surface ─────────────────────────────────── */
  --nv2-bg:            #f6f7fb;
  --nv2-bg-2:          #eef0f6;
  --nv2-panel:         #ffffff;
  --nv2-panel-2:       #fafbff;
  --nv2-rail:          #0b1220;
  --nv2-rail-2:        #131c2f;

  /* ── Foreground ──────────────────────────────── */
  --nv2-rail-fg:       #cbd5e1;
  --nv2-rail-fg-mute:  #6b7693;
  --nv2-ink:           #0f172a;
  --nv2-ink-2:         #475569;
  --nv2-ink-3:         #94a3b8;
  --nv2-ink-4:         #cbd5e1;

  /* ── Borders ────────────────────────────────── */
  --nv2-line:          #e6e8ef;
  --nv2-line-2:        #eef0f6;

  /* ── Brand + accents ────────────────────────── */
  --nv2-brand:         #4361ee;
  --nv2-brand-2:       #5b8def;
  --nv2-brand-soft:    #eaf0ff;
  --nv2-accent:        #ff5d73;
  --nv2-warn:          #f59e0b;
  --nv2-warn-soft:     #fef3c7;
  --nv2-ok:            #10b981;
  --nv2-ok-soft:       #d1fae5;
  --nv2-danger:        #ef4444;
  --nv2-danger-soft:   #fee2e2;

  /* ── Hub accent (override per hub) ──────────── */
  --nv2-hub-accent:    var(--nv2-brand);

  /* ── Shadows ────────────────────────────────── */
  --nv2-shadow-xs:     0 1px 2px rgba(15, 23, 42, 0.04);
  --nv2-shadow-sm:     0 2px 6px rgba(15, 23, 42, 0.06);
  --nv2-shadow-md:     0 8px 24px -8px rgba(15, 23, 42, 0.10);
  --nv2-shadow-lg:     0 24px 60px -20px rgba(15, 23, 42, 0.18);
  --nv2-shadow-xl:     0 40px 100px -30px rgba(15, 23, 42, 0.30);

  /* ── Radii ──────────────────────────────────── */
  --nv2-radius:        12px;
  --nv2-radius-sm:     8px;
  --nv2-radius-lg:     16px;

  /* ── Type ───────────────────────────────────── */
  --nv2-font-display:  'Sora', 'Manrope', system-ui, sans-serif;
  --nv2-font-body:     'Manrope', system-ui, sans-serif;
  --nv2-font-mono:     'Sora', ui-monospace, SFMono-Regular, Menlo, monospace;
}

/* ═══════════════════════════════════════════════════════════════════════════
   GLOBAL — only applied inside .nv2-scope so we don't override the legacy app
   ═══════════════════════════════════════════════════════════════════════════ */
.nv2-scope {
  font-family: var(--nv2-font-body);
  color: var(--nv2-ink);
  background: var(--nv2-bg);
  -webkit-font-smoothing: antialiased;
}
.nv2-scope h1, .nv2-scope h2, .nv2-scope h3, .nv2-scope h4 {
  font-family: var(--nv2-font-display);
  letter-spacing: -0.015em;
  margin: 0;
  font-weight: 700;
}
.nv2-scope ::-webkit-scrollbar { width: 8px; height: 8px; }
.nv2-scope ::-webkit-scrollbar-thumb { background: rgba(100, 116, 139, 0.22); border-radius: 999px; }
.nv2-scope ::-webkit-scrollbar-thumb:hover { background: rgba(100, 116, 139, 0.4); }
.nv2-scope ::-webkit-scrollbar-track { background: transparent; }
.nv2-scope mark { background: var(--nv2-brand-soft); color: var(--nv2-brand); padding: 0 2px; border-radius: 3px; }

/* ═══════════════════════════════════════════════════════════════════════════
   APP SHELL — Rail + HubPanel + Main
   ═══════════════════════════════════════════════════════════════════════════ */
.nv2-app {
  display: grid;
  grid-template-columns: 72px 296px 1fr;
  height: 100vh;
  overflow: hidden;
  /* The prototype HTML had a `position: fixed; top: 0` "Prototype · NobleNeo
     v2 · …" preview banner across the top, which required reserving 28px at
     the top of .nv2-app and offsetting .nv2-rail by 28px. The deployed shell
     does NOT render that banner, so the reserved 28px showed up as a visible
     grey strip across the top of every page. Remove the offsets so the rail
     and panes fill the viewport edge-to-edge. */
  transition: grid-template-columns 240ms cubic-bezier(0.16, 1, 0.3, 1);
}
/* When the rail is PINNED open (240px wide and stays), expand the first grid
   column so the HubPanel + Main pane shift right. Without this, the pinned
   rail (position: fixed, z-index: 100) overlaps the panel's leftmost 168px
   and intercepts clicks. Hover-expansion still overlays — see Rail's onClick
   for the auto-collapse-after-hub-click handling. */
.nv2-app.is-rail-pinned {
  grid-template-columns: 240px 296px 1fr;
}
/* AVMENU-2 (2026-09-06) — THE PERSONAL PAGES RESERVE NO HUB COLUMN. The four
   pages that belong to the person and to no hub (config/personal-pages.js, plus
   their sign-in doors) draw no hub panel, so without this their content started
   296px in behind an empty grey band — the measured `hubPanelWidth: 296` with
   nothing in it. shell.jsx sets the class only while `hubPanelHidden`; one rail
   hub click clears it and the column comes back.

   IT LIVES AT THE BASE, NOT IN A DESKTOP-BAND MEDIA BLOCK. DASH-105's shape is
   that the base rules ARE the desktop layout and every responsive rule is a
   max-width override, and its R2 asserts the desktop band carries no media block
   at all; a first cut of this added one and reddened that guard. The two narrow bands
   therefore re-declare this pair beside their own `.nv2-app` rules below, because
   a two-class selector here out-specifies their one-class one. */
.nv2-app.is-no-hub-panel {
  grid-template-columns: 72px 0 1fr;
}
.nv2-app.is-rail-pinned.is-no-hub-panel {
  grid-template-columns: 240px 0 1fr;
}
.nv2-pane {
  height: 100vh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
.nv2-hub-panel-col { grid-column: 2; }
.nv2-main-col      { grid-column: 3; }

/* ── Rail ─────────────────────────────────────── */
.nv2-rail {
  position: fixed;
  top: 0; left: 0; bottom: 0;
  width: 72px;
  background: linear-gradient(180deg, var(--nv2-rail) 0%, var(--nv2-rail-2) 100%);
  color: var(--nv2-rail-fg);
  align-items: stretch;
  padding: 14px 12px;
  gap: 4px;
  z-index: 100;
  overflow: hidden;
  transition: width 240ms cubic-bezier(0.16, 1, 0.3, 1), box-shadow 240ms ease;
  will-change: width;
}
/* Expand the rail when the cursor is over it OR when the JS-controlled
   .is-hover / .is-pinned classes are present. The earlier "JS-only" model
   (no native :hover) silently failed when the JS hover-intent timer was
   cancelled by an unrelated re-render or a slow main thread — the rail
   would simply not expand on hover. Adding native :hover as a parallel
   trigger is a CSS-only fallback that works regardless of JS state. The
   .nv2-rail.is-collapsed-after-click class temporarily wins (via
   !important) so the auto-collapse-after-hub-click behavior still fires
   when needed. */
.nv2-rail:hover, .nv2-rail.is-hover, .nv2-rail.is-pinned {
  width: 240px;
  box-shadow: 18px 0 56px -16px rgba(15, 23, 42, 0.42);
}
.nv2-rail.is-collapsed-after-click {
  width: 72px !important;
  box-shadow: none !important;
}

.nv2-brand-row {
  display: flex; align-items: center; gap: 12px;
  padding: 0 4px; margin-bottom: 8px; height: 40px;
}
.nv2-brand-mark {
  width: 40px; height: 40px;
  flex-shrink: 0;
  border-radius: 10px;
  background: linear-gradient(135deg, var(--nv2-brand) 0%, #7c3aed 100%);
  display: grid; place-items: center;
  color: white;
  font-family: var(--nv2-font-display);
  font-weight: 800; font-size: 17px;
  letter-spacing: -0.04em;
  box-shadow: 0 6px 20px rgba(67, 97, 238, 0.4);
}
.nv2-brand-text-wrap {
  opacity: 0;
  transform: translateX(-8px);
  transition: opacity 200ms ease 60ms, transform 240ms cubic-bezier(0.16, 1, 0.3, 1) 60ms;
  white-space: nowrap;
}
.nv2-rail:hover .nv2-brand-text-wrap,
.nv2-rail.is-hover .nv2-brand-text-wrap,
.nv2-rail.is-pinned .nv2-brand-text-wrap { opacity: 1; transform: translateX(0); }
.nv2-rail.is-collapsed-after-click .nv2-brand-text-wrap { opacity: 0 !important; transform: translateX(-8px) !important; }
.nv2-brand-text {
  font-family: var(--nv2-font-display);
  font-size: 17px; font-weight: 800;
  color: white; letter-spacing: -0.02em; line-height: 1;
}
.nv2-brand-sub {
  font-size: 10.5px; font-weight: 600;
  color: var(--nv2-rail-fg-mute);
  margin-top: 2px;
  text-transform: uppercase; letter-spacing: 0.08em;
}
.nv2-rail-divider {
  height: 1px;
  background: rgba(255,255,255,0.06);
  margin: 6px 4px;
}
.nv2-rail-section {
  font-size: 10px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.12em;
  color: rgba(255,255,255,0.32);
  padding: 10px 12px 4px;
  white-space: nowrap;
  opacity: 0; transition: opacity 180ms ease 80ms;
}
.nv2-rail:hover .nv2-rail-section,
.nv2-rail.is-hover .nv2-rail-section,
.nv2-rail.is-pinned .nv2-rail-section { opacity: 1; }
.nv2-rail.is-collapsed-after-click .nv2-rail-section { opacity: 0 !important; }
.nv2-hub-btn {
  position: relative;
  width: 100%; height: 40px;
  border: 0; background: transparent;
  color: var(--nv2-rail-fg-mute);
  border-radius: 9px;
  cursor: pointer;
  display: flex; align-items: center; gap: 12px;
  padding: 0 12px;
  font-family: inherit;
  transition: background 160ms ease, color 160ms ease;
}
.nv2-hub-btn svg {
  width: 19px; height: 19px; stroke-width: 2; flex-shrink: 0;
  transition: transform 180ms cubic-bezier(0.16, 1, 0.3, 1), color 160ms ease;
}
.nv2-hub-btn:hover { background: rgba(255,255,255,0.06); color: white; }
.nv2-hub-btn:hover svg { transform: scale(1.18); }

/* Per-icon tooltip — surfaces the section name when the rail is collapsed
   so the icon-only state isn't a guessing game. Suppressed once the rail
   itself is hovered/pinned because the in-rail label is already visible. */
.nv2-hub-btn[data-tooltip]::after {
  content: attr(data-tooltip);
  position: absolute;
  left: calc(100% + 14px); top: 50%;
  transform: translateY(-50%) translateX(-4px);
  background: rgba(15, 18, 30, 0.96);
  color: white;
  font-size: 12px; font-weight: 600;
  padding: 6px 10px;
  border-radius: 6px;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transition: opacity 140ms ease, transform 140ms ease;
  z-index: 1100;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5);
}
.nv2-hub-btn[data-tooltip]:hover::after {
  opacity: 1;
  transform: translateY(-50%) translateX(0);
}
/* Only suppress the floating tooltip when the rail is *pinned* open. In the
   transient hover-expanded state we still want it — without this, the parent
   .nv2-rail:hover selector cancels the tooltip the moment the cursor enters
   any icon (the icon is a child of the rail), making it look like nothing
   happens on hover. */
.nv2-rail.is-pinned .nv2-hub-btn[data-tooltip]::after { opacity: 0 !important; }
.nv2-hub-btn.is-active {
  background: rgba(255, 255, 255, 0.06);
  color: white;
}
.nv2-hub-btn.is-active::before {
  content: '';
  position: absolute;
  left: -12px; top: 8px; bottom: 8px;
  width: 3px; border-radius: 0 3px 3px 0;
  background: var(--nv2-hub-accent, var(--nv2-brand-2));
  box-shadow: 0 0 12px var(--nv2-hub-accent, var(--nv2-brand-2));
}
.nv2-hub-btn.is-active svg { color: var(--nv2-hub-accent, var(--nv2-brand-2)); }
.nv2-hub-label {
  font-size: 13.5px; font-weight: 600;
  white-space: nowrap;
  opacity: 0; transform: translateX(-8px);
  transition: opacity 200ms ease 80ms, transform 240ms cubic-bezier(0.16, 1, 0.3, 1) 80ms;
}
.nv2-rail:hover .nv2-hub-label,
.nv2-rail.is-hover .nv2-hub-label,
.nv2-rail.is-pinned .nv2-hub-label { opacity: 1; transform: translateX(0); }
.nv2-rail.is-collapsed-after-click .nv2-hub-label { opacity: 0 !important; transform: translateX(-8px) !important; }
.nv2-hub-badge {
  position: absolute;
  top: 4px; right: 4px;
  background: var(--nv2-accent);
  color: white;
  font-size: 9px; font-weight: 700;
  padding: 1px 5px;
  border-radius: 999px;
  line-height: 1.4;
}
.nv2-rail:hover .nv2-hub-badge,
.nv2-rail.is-hover .nv2-hub-badge,
.nv2-rail.is-pinned .nv2-hub-badge {
  position: static; margin-left: auto;
  font-size: 10.5px; padding: 2px 7px;
}
.nv2-rail-spacer { flex: 1; }
.nv2-rail-bottom { display: flex; flex-direction: column; gap: 2px; }
.nv2-rail-pin {
  position: absolute;
  top: 22px; right: 14px;
  width: 26px; height: 26px;
  border: 0; background: rgba(255,255,255,0.06);
  color: var(--nv2-rail-fg);
  border-radius: 7px;
  cursor: pointer;
  opacity: 0;
  display: grid; place-items: center;
  transition: opacity 200ms ease 100ms, background 160ms ease;
}
.nv2-rail:hover .nv2-rail-pin,
.nv2-rail.is-hover .nv2-rail-pin,
.nv2-rail.is-pinned .nv2-rail-pin { opacity: 1; }
.nv2-rail.is-collapsed-after-click .nv2-rail-pin { opacity: 0 !important; }
.nv2-rail-pin:hover { background: rgba(255,255,255,0.16); color: white; }
.nv2-rail-pin svg { width: 13px; height: 13px; }
.nv2-rail.is-pinned .nv2-rail-pin { background: var(--nv2-brand); color: white; }

/* ── Hub Panel ─────────────────────────────────── */
.nv2-hub-panel {
  background: var(--nv2-panel);
  border-right: 1px solid var(--nv2-line);
}
.nv2-hub-header {
  position: relative;
  padding: 18px 20px 14px;
  border-bottom: 1px solid var(--nv2-line-2);
  background: linear-gradient(135deg,
    color-mix(in srgb, var(--nv2-hub-accent, var(--nv2-brand)) 8%, var(--nv2-panel)) 0%,
    var(--nv2-panel) 70%);
  overflow: hidden;
}
.nv2-hub-header::after {
  content: '';
  position: absolute;
  top: -40px; right: -40px;
  width: 140px; height: 140px;
  border-radius: 50%;
  background: radial-gradient(circle, color-mix(in srgb, var(--nv2-hub-accent, var(--nv2-brand)) 14%, transparent) 0%, transparent 70%);
  pointer-events: none;
}
.nv2-hub-eyebrow {
  font-size: 10.5px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.12em;
  color: var(--nv2-hub-accent, var(--nv2-brand));
  margin-bottom: 4px;
}
.nv2-hub-title { font-size: 19px; font-weight: 700; }
.nv2-hub-meta { font-size: 12px; color: var(--nv2-ink-2); margin-top: 2px; }
.nv2-hub-quick-action {
  display: inline-flex; align-items: center; gap: 6px;
  margin-top: 14px;
  padding: 7px 12px;
  background: var(--nv2-hub-accent, var(--nv2-brand));
  color: white;
  border: 0; border-radius: 7px;
  font-family: inherit; font-size: 12.5px; font-weight: 700;
  cursor: pointer;
  text-decoration: none;
  box-shadow: 0 4px 12px color-mix(in srgb, var(--nv2-hub-accent, var(--nv2-brand)) 40%, transparent);
  transition: transform 160ms ease, box-shadow 160ms ease;
}
.nv2-hub-quick-action:hover {
  transform: translateY(-1px);
  box-shadow: 0 6px 16px color-mix(in srgb, var(--nv2-hub-accent, var(--nv2-brand)) 50%, transparent);
}
.nv2-hub-quick-action svg { width: 13px; height: 13px; }

.nv2-hub-search {
  position: relative;
  margin: 12px 16px 0;
}
.nv2-hub-search input {
  width: 100%;
  padding: 8px 12px 8px 32px;
  border-radius: 8px;
  border: 1px solid var(--nv2-line);
  background: var(--nv2-panel-2);
  font-family: inherit; font-size: 13px;
  outline: none;
  transition: all 160ms ease;
}
.nv2-hub-search input:focus {
  border-color: var(--nv2-hub-accent, var(--nv2-brand));
  background: white;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--nv2-hub-accent, var(--nv2-brand)) 14%, transparent);
}
.nv2-hub-search > svg {
  position: absolute;
  left: 10px; top: 50%; transform: translateY(-50%);
  width: 14px; height: 14px;
  color: var(--nv2-ink-3);
}
.nv2-hub-list {
  flex: 1;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 8px 22px 24px 8px;
  scrollbar-gutter: stable;
  scrollbar-width: thin;
  scrollbar-color: var(--nv2-line) transparent;
}
.nv2-hub-list::-webkit-scrollbar { width: 6px; height: 6px; }
.nv2-hub-list::-webkit-scrollbar-track { background: transparent; margin: 4px 0; }
.nv2-hub-list::-webkit-scrollbar-thumb {
  background: var(--nv2-line);
  border-radius: 999px;
  border: 1px solid transparent;
  background-clip: content-box;
}
.nv2-hub-list:hover::-webkit-scrollbar-thumb { background: var(--nv2-ink-3); background-clip: content-box; }
.nv2-hub-list::-webkit-scrollbar-thumb:hover { background: var(--nv2-hub-accent, var(--nv2-brand)); background-clip: content-box; }
.nv2-hub-list::-webkit-scrollbar-corner { background: transparent; }

.nv2-pinned-strip { padding: 12px 16px 0; border-bottom: 1px solid var(--nv2-line-2); margin-bottom: 6px; }
.nv2-group-label {
  font-size: 10px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.10em;
  color: var(--nv2-ink-3);
  padding: 6px 4px;
  display: flex; align-items: center; gap: 8px;
}
.nv2-pin-row { display: flex; flex-wrap: wrap; gap: 6px; padding-bottom: 12px; }
.nv2-pin-chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 10px 4px 8px;
  background: var(--nv2-panel-2);
  border: 1px solid var(--nv2-line);
  border-radius: 999px;
  font-size: 12px; font-weight: 600;
  color: var(--nv2-ink);
  cursor: pointer;
  text-decoration: none;
  transition: all 140ms ease;
  white-space: nowrap;
}
.nv2-pin-chip:hover {
  border-color: var(--nv2-hub-accent, var(--nv2-brand));
  color: var(--nv2-hub-accent, var(--nv2-brand));
  transform: translateY(-1px);
}
.nv2-pin-chip svg { width: 12px; height: 12px; }
.nv2-pin-chip.is-recent { background: white; border-style: dashed; color: var(--nv2-ink-2); }

/* ── Module rows ─────────────────────────────── */
.nv2-module { margin: 0 8px 1px; }
.nv2-module-btn {
  display: flex; align-items: center; gap: 10px;
  width: 100%; padding: 8px 12px;
  border: 0; background: transparent;
  color: var(--nv2-ink);
  border-radius: 8px;
  cursor: pointer;
  font-family: inherit; font-size: 13.5px; font-weight: 500;
  text-align: left;
  transition: background 140ms ease, color 140ms ease;
}
.nv2-module-btn:hover { background: var(--nv2-panel-2); }
.nv2-module-btn.is-expanded {
  background: color-mix(in srgb, var(--nv2-hub-accent, var(--nv2-brand)) 10%, white);
  color: var(--nv2-hub-accent, var(--nv2-brand));
}
.nv2-module-btn .nv2-chev {
  margin-left: auto;
  transition: transform 200ms ease;
  width: 14px; height: 14px;
  color: var(--nv2-ink-3);
}
.nv2-module-btn.is-expanded .nv2-chev { transform: rotate(90deg); }
.nv2-module-btn .nv2-icon { width: 16px; height: 16px; flex-shrink: 0; opacity: 0.85; }
/* D29-D-5 (2026-09-04) — the count pill wrapped MID-NUMBER. Measured at
   390x844 on staging deploy #29: every two-digit group count rendered over two
   lines — "24" read as "2 / 4", "11" as "1 / 1", "19" as "1 / 9" — at 31px tall
   against 16-19px for a single digit. Two causes, both fixed here and on the
   `.nv2-subgroup-btn` sibling below so the SECTIONS do not keep the defect:
   the pill is a flex item with the default `flex: 0 1 auto`, so a narrow drawer
   shrank it below its content and the text broke at the only place it could —
   between the digits; and nothing forbade that break. `nowrap` forbids it and
   `flex-shrink: 0` stops the squeeze. The min-width is the two-digit width, so
   1 and 99 draw the same pill and the number stays centred — stated with an
   explicit `box-sizing` because it is the difference between 28px meaning "the
   whole pill" and "the pill plus its 14px of padding", and the reset that
   currently decides it (`*,:after,:before{box-sizing:border-box}` in the
   Bootstrap-derived theme.min.css, loaded before this sheet) is not ours to
   depend on. Nothing else about the button changes. */
.nv2-module-btn .nv2-count {
  font-size: 11px; font-weight: 600;
  color: var(--nv2-ink-3);
  background: var(--nv2-bg);
  padding: 1px 7px;
  border-radius: 999px;
  margin-left: 6px;
  white-space: nowrap;
  flex: 0 0 auto;
  box-sizing: border-box;
  min-width: 28px;
  text-align: center;
}
.nv2-module-btn.is-expanded .nv2-count {
  background: white;
  color: var(--nv2-hub-accent, var(--nv2-brand));
  font-weight: 700;
}
.nv2-module-btn .nv2-alert-dot {
  width: 6px; height: 6px;
  background: var(--nv2-accent);
  border-radius: 50%;
}
.nv2-module-children { max-height: 0; overflow: hidden; transition: max-height 320ms cubic-bezier(0.4, 0, 0.2, 1); }
/* Larger ceiling so a module with a nested children tree (e.g. SEPA Engine:
   17 leaves + 3 expandable sub-groups) is not clipped when sub-groups open. */
.nv2-module-children.is-open { max-height: 2400px; }
.nv2-module-children ul { list-style: none; margin: 4px 0 6px; padding: 0; }

/* 3rd-level nested sub-groups (NPN-SEPA-INTO-TREASURY): Transfers / Rules Engine
   / Queues inside the SEPA Engine module. */
.nv2-subgroup { list-style: none; }
.nv2-subgroup-btn {
  display: flex; align-items: center; gap: 8px; width: calc(100% - 8px);
  padding: 6px 12px 6px 38px; margin: 0 4px;
  font-size: 13px; font-weight: 500; color: var(--nv2-ink-2);
  background: none; border: 0; border-radius: 6px; cursor: pointer; text-align: left;
}
.nv2-subgroup-btn:hover { background: var(--nv2-panel-2); color: var(--nv2-ink); }
/* D29-D-5: the section pill carries the same guard as the group pill above —
   the sections are narrower than the groups, so they wrap first. */
.nv2-subgroup-btn .nv2-count {
  margin-left: auto;
  font-size: 11px; font-weight: 600;
  color: var(--nv2-ink-3);
  background: var(--nv2-bg);
  padding: 1px 7px;
  border-radius: 999px;
  white-space: nowrap;
  flex: 0 0 auto;
  box-sizing: border-box;
  min-width: 28px;
  text-align: center;
}
.nv2-subgroup-btn.is-expanded .nv2-count {
  background: white;
  color: var(--nv2-hub-accent, var(--nv2-brand));
}
.nv2-subgroup-btn .nv2-chev { transition: transform 160ms ease; }
.nv2-subgroup-btn.is-expanded .nv2-chev { transform: rotate(90deg); }
.nv2-subgroup-children { max-height: 0; overflow: hidden; transition: max-height 280ms cubic-bezier(0.4, 0, 0.2, 1); }
.nv2-subgroup-children.is-open { max-height: 600px; }
.nv2-subgroup-children li a { padding-left: 54px; }  /* deeper indent for the 3rd level */
.nv2-module-children li a {
  display: flex; align-items: center; gap: 8px;
  padding: 6px 12px 6px 38px;
  font-size: 13px;
  color: var(--nv2-ink-2);
  text-decoration: none;
  border-radius: 6px;
  margin: 0 4px;
  transition: all 120ms ease;
}
.nv2-module-children li a:hover { background: var(--nv2-panel-2); color: var(--nv2-ink); }
.nv2-module-children li a.is-active {
  background: var(--nv2-hub-accent, var(--nv2-brand));
  color: white; font-weight: 600;
}
.nv2-module-children li a .nv2-leaf-badge {
  margin-left: auto;
  background: var(--nv2-accent);
  color: white;
  font-size: 10px; font-weight: 700;
  padding: 1px 6px;
  border-radius: 999px;
}
/* NPN-ACR-7b: leaf-level LIVE work-item count pill (My Work / Team Queues /
   SLA Monitor / Escalations). Distinct from .nv2-leaf-badge (accent-red alert
   dot) — same visual weight as the module-level .nv2-count pill so it reads
   as a count, not an alert. Inverts colour on the active leaf so it stays
   legible against the accent background. */
.nv2-module-children li a .nv2-leaf-count {
  margin-left: auto;
  background: var(--nv2-bg);
  color: var(--nv2-ink-3);
  font-size: 11px; font-weight: 600;
  padding: 1px 7px;
  border-radius: 999px;
}
.nv2-module-children li a.is-active .nv2-leaf-count {
  background: rgba(255, 255, 255, 0.22);
  color: white;
}

/* ── Topbar ────────────────────────────────────── */
.nv2-main { background: var(--nv2-bg); }
.nv2-topbar {
  height: 60px;
  background: white;
  border-bottom: 1px solid var(--nv2-line);
  display: flex; align-items: center; gap: 12px;
  padding: 0 20px;
  position: relative;
  z-index: 10;
}
.nv2-breadcrumb {
  display: flex; align-items: center; gap: 6px;
  font-size: 13px; color: var(--nv2-ink-2);
}
.nv2-breadcrumb a { color: var(--nv2-ink-2); text-decoration: none; }
.nv2-breadcrumb a:hover { color: var(--nv2-brand); }
.nv2-breadcrumb .nv2-crumb-current { color: var(--nv2-ink); font-weight: 600; }
.nv2-breadcrumb .nv2-sep { color: var(--nv2-ink-4); font-weight: 300; }

.nv2-env-chip {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 9px;
  background: var(--nv2-warn-soft);
  color: #92400e;
  border: 1px solid #fde68a;
  border-radius: 999px;
  font-size: 10.5px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.05em;
  margin-left: 8px;
}
.nv2-env-chip::before {
  content: '';
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--nv2-warn);
  box-shadow: 0 0 8px var(--nv2-warn);
  animation: nv2-pulse 2.4s ease-in-out infinite;
}
@keyframes nv2-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } }

.nv2-path-tag {
  display: inline-flex; align-items: center;
  font-family: var(--nv2-font-mono);
  font-size: 11px; font-weight: 600;
  color: var(--nv2-ink-3);
  background: var(--nv2-bg);
  padding: 3px 9px;
  border-radius: 6px;
  margin-left: 8px;
  letter-spacing: -0.01em;
}
.nv2-path-tag::before {
  content: '⌥';
  margin-right: 5px;
  opacity: 0.5;
  font-weight: 800;
}

.nv2-topbar-search {
  flex: 1; max-width: 460px; margin-left: auto;
  position: relative;
}
.nv2-topbar-search input {
  width: 100%;
  padding: 9px 12px 9px 36px;
  border-radius: 10px;
  border: 1px solid var(--nv2-line);
  background: var(--nv2-bg);
  font-family: inherit; font-size: 13px;
  outline: none;
  transition: all 160ms ease;
}
.nv2-topbar-search input:focus, .nv2-topbar-search input:hover {
  border-color: var(--nv2-brand); background: white;
}
.nv2-topbar-search > svg {
  position: absolute;
  left: 12px; top: 50%; transform: translateY(-50%);
  width: 16px; height: 16px;
  color: var(--nv2-ink-3);
}
.nv2-topbar-search kbd {
  position: absolute; right: 10px; top: 50%; transform: translateY(-50%);
  font-family: inherit;
  font-size: 11px; font-weight: 600;
  background: white;
  border: 1px solid var(--nv2-line);
  padding: 2px 6px;
  border-radius: 4px;
  color: var(--nv2-ink-2);
}
.nv2-topbar-icon {
  width: 36px; height: 36px;
  border-radius: 50%;
  display: grid; place-items: center;
  cursor: pointer;
  color: var(--nv2-ink-2);
  transition: all 140ms ease;
  position: relative;
  border: 0; background: transparent;
}
.nv2-topbar-icon:hover { background: var(--nv2-bg); color: var(--nv2-brand); }
.nv2-topbar-icon .nv2-dot {
  position: absolute; top: 9px; right: 10px;
  width: 8px; height: 8px;
  background: var(--nv2-accent);
  border-radius: 50%;
  border: 2px solid white;
}
.nv2-avatar-btn {
  width: 36px; height: 36px;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--nv2-brand) 0%, var(--nv2-accent) 100%);
  display: grid; place-items: center;
  color: white; font-weight: 700; font-size: 13px;
  cursor: pointer;
  border: 2px solid white;
  box-shadow: var(--nv2-shadow-sm);
  transition: transform 160ms ease;
}
.nv2-avatar-btn:hover { transform: scale(1.05); }

/* ── Content ───────────────────────────────────── */
.nv2-content { flex: 1; min-height: 0; overflow-y: auto; padding: 24px 28px 64px; }

/* Neutralise legacy .app-content-area wrapper used by 122 parent route files
   (e.g. routes/dashboard.jsx wraps <Outlet/> in <div className="app-content-area">).
   Inside the v2 shell that legacy class injects:
     - background: #f5f5f7 !important   → visible grey strip above page content
     - min-height: 100vh                → forces extra blank scroll area
     - padding: 70px 10px 20px @ ≤768px → 70px grey bar at top on mobile
     - animation: fadeIn                → unwanted opacity flash on nav
   Strip all of it when nested inside .nv2-content (or any v2 scope). */
.nv2-scope .app-content-area,
.nv2-content .app-content-area {
  background: transparent !important;
  background-color: transparent !important;
  min-height: auto !important;
  animation: none !important;
  padding: 0 !important;
  margin: 0 !important;
}
.nv2-scope .container-fluid,
.nv2-content .container-fluid { padding: 0 !important; }

/* Defense-in-depth: hide any orphaned debug pills (path-tag was removed from
   shell.jsx Topbar in commit bd062cd but the CSS class still exists in this
   file and could re-appear if something imports PathTag from primitives.jsx). */
.nv2-scope .nv2-path-tag,
.nv2-topbar .nv2-path-tag { display: none !important; }
.nv2-page-header {
  margin-bottom: 18px;
  display: flex; align-items: end; justify-content: space-between;
  gap: 16px;
}
.nv2-page-header .nv2-title h1 { font-size: 26px; font-weight: 700; }
.nv2-page-header .nv2-title p { color: var(--nv2-ink-2); font-size: 13.5px; margin: 4px 0 0; }
.nv2-page-actions { display: flex; gap: 8px; }

/* ═══════════════════════════════════════════════════════════════════════════
   PRIMITIVES — Buttons, Pills, Avatars, Toast, Stepper
   ═══════════════════════════════════════════════════════════════════════════ */

.nv2-btn {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 8px 14px;
  border-radius: 8px;
  font-family: inherit; font-size: 13px; font-weight: 600;
  cursor: pointer;
  border: 1px solid var(--nv2-line);
  background: white;
  color: var(--nv2-ink);
  text-decoration: none;
  transition: all 140ms ease;
  white-space: nowrap;
}
.nv2-btn:hover { border-color: var(--nv2-hub-accent, var(--nv2-brand)); color: var(--nv2-hub-accent, var(--nv2-brand)); }
.nv2-btn:disabled { opacity: 0.5; cursor: not-allowed; }
.nv2-btn-primary {
  background: var(--nv2-hub-accent, var(--nv2-brand));
  color: white;
  border-color: var(--nv2-hub-accent, var(--nv2-brand));
  box-shadow: 0 4px 12px color-mix(in srgb, var(--nv2-hub-accent, var(--nv2-brand)) 30%, transparent);
}
.nv2-btn-primary:hover {
  filter: brightness(1.08);
  color: white;
  transform: translateY(-1px);
  box-shadow: 0 6px 16px color-mix(in srgb, var(--nv2-hub-accent, var(--nv2-brand)) 40%, transparent);
}
/* NPN-REMIT-LIST-MOCKUP-2 (2026-06-01): brand-blue variant that ignores
   the per-hub accent (which on Remittance is green). Used for the
   primary "+ New remittance" CTA where the mockup explicitly shows
   blue regardless of which hub the operator is in. */
.nv2-btn-brand {
  background: var(--nv2-brand);
  color: white;
  border-color: var(--nv2-brand);
  box-shadow: 0 4px 12px color-mix(in srgb, var(--nv2-brand) 30%, transparent);
}
.nv2-btn-brand:hover {
  filter: brightness(1.08);
  color: white;
  transform: translateY(-1px);
  box-shadow: 0 6px 16px color-mix(in srgb, var(--nv2-brand) 40%, transparent);
}
.nv2-btn-danger { border-color: var(--nv2-danger); color: var(--nv2-danger); }
.nv2-btn-warn { border-color: var(--nv2-warn); color: #92400e; }
.nv2-btn svg { width: 14px; height: 14px; }
.nv2-btn-icon { padding: 8px; width: 36px; height: 36px; justify-content: center; }
.nv2-btn-block { width: 100%; justify-content: flex-start; }

/* NPN-UX-BTN-LOADING — in-flight API-call state. <Button loading> swaps the
   icon for a spinning Loader2 and disables the button until the fetcher /
   navigation settles. */
.nv2-btn-loading { pointer-events: none; opacity: 0.75; }
.nv2-btn-spinner { animation: nv2-btn-spin 0.7s linear infinite; }
@keyframes nv2-btn-spin { to { transform: rotate(360deg); } }

/* Pills (status indicators) */
.nv2-pill {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 2px 9px;
  border-radius: 999px;
  font-size: 11px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.04em;
  white-space: nowrap;
}
.nv2-pill::before { content: ''; width: 6px; height: 6px; border-radius: 50%; }
.nv2-pill-created     { background: #e0e7ff; color: #3730a3; }
.nv2-pill-created::before { background: #6366f1; }
.nv2-pill-pending     { background: var(--nv2-warn-soft); color: #92400e; }
.nv2-pill-pending::before { background: var(--nv2-warn); }
.nv2-pill-checked     { background: #cffafe; color: #155e75; }
.nv2-pill-checked::before { background: #06b6d4; }
.nv2-pill-held        { background: var(--nv2-danger-soft); color: #991b1b; }
.nv2-pill-held::before { background: var(--nv2-danger); }
.nv2-pill-sent        { background: #ede9fe; color: #5b21b6; }
.nv2-pill-sent::before { background: #7c3aed; }
.nv2-pill-paid        { background: var(--nv2-ok-soft); color: #065f46; }
.nv2-pill-paid::before { background: var(--nv2-ok); }
.nv2-pill-cancelled   { background: #f3f4f6; color: #4b5563; }
.nv2-pill-cancelled::before { background: #9ca3af; }
.nv2-pill-error       { background: var(--nv2-danger-soft); color: #991b1b; }
.nv2-pill-error::before { background: var(--nv2-danger); }
.nv2-pill-locked      { background: #fef3c7; color: #92400e; }
.nv2-pill-locked::before { background: #f59e0b; }
.nv2-pill-kyc-verified { background: var(--nv2-ok-soft); color: #065f46; }
.nv2-pill-kyc-verified::before { background: var(--nv2-ok); }
.nv2-pill-kyc-pending  { background: var(--nv2-warn-soft); color: #92400e; }
.nv2-pill-kyc-pending::before { background: var(--nv2-warn); }
.nv2-pill-kyc-failed   { background: var(--nv2-danger-soft); color: #991b1b; }
.nv2-pill-kyc-failed::before { background: var(--nv2-danger); }
.nv2-pill-high-risk    { background: var(--nv2-danger-soft); color: #991b1b; }
.nv2-pill-high-risk::before { background: var(--nv2-danger); }
.nv2-pill-medium-risk  { background: var(--nv2-warn-soft); color: #92400e; }
.nv2-pill-medium-risk::before { background: var(--nv2-warn); }
.nv2-pill-low-risk     { background: var(--nv2-ok-soft); color: #065f46; }
.nv2-pill-low-risk::before { background: var(--nv2-ok); }
.nv2-pill-candidate    { background: #fef3c7; color: #92400e; }
.nv2-pill-candidate::before { background: #f59e0b; }
.nv2-pill-confirmed    { background: var(--nv2-danger-soft); color: #991b1b; }
.nv2-pill-confirmed::before { background: var(--nv2-danger); }
.nv2-pill-merged       { background: #ede9fe; color: #5b21b6; }
.nv2-pill-merged::before { background: #7c3aed; }
.nv2-pill-rejected     { background: #f3f4f6; color: #4b5563; }
.nv2-pill-rejected::before { background: #9ca3af; }

/* Avatar */
.nv2-avatar {
  display: grid; place-items: center;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--nv2-brand) 0%, #7c3aed 100%);
  color: white;
  font-weight: 700;
  font-family: var(--nv2-font-display);
  flex-shrink: 0;
}
.nv2-avatar-sm { width: 28px; height: 28px; font-size: 10px; }
.nv2-avatar-md { width: 36px; height: 36px; font-size: 13px; }
.nv2-avatar-lg { width: 44px; height: 44px; font-size: 16px; }
.nv2-avatar-xl { width: 64px; height: 64px; font-size: 22px; }

/* Flag circles */
.nv2-flag {
  display: inline-grid; place-items: center;
  border-radius: 50%;
  font-size: 9px; font-weight: 800;
  text-transform: uppercase;
  flex-shrink: 0;
  width: 22px; height: 22px;
  background: linear-gradient(135deg, #4361ee 0%, #7c3aed 100%);
  color: white;
}
.nv2-flag-gb { background: linear-gradient(135deg, #c8102e 50%, #012169 50%); color: white; }
.nv2-flag-ng { background: linear-gradient(90deg, #008751 33.3%, white 33.3% 66.6%, #008751 66.6%); color: #064e3b; }
.nv2-flag-in { background: linear-gradient(180deg, #ff9933 33.3%, white 33.3% 66.6%, #138808 66.6%); color: #1e293b; }
.nv2-flag-us { background: linear-gradient(180deg, #b22234 50%, #3c3b6e 50%); color: white; }
.nv2-flag-fr { background: linear-gradient(90deg, #002395 33.3%, white 33.3% 66.6%, #ed2939 66.6%); color: #1e293b; }
.nv2-flag-de { background: linear-gradient(180deg, #000 33.3%, #dd0000 33.3% 66.6%, #ffce00 66.6%); color: white; }
.nv2-flag-ae { background: linear-gradient(180deg, #00732f 33.3%, white 33.3% 66.6%, #000 66.6%); color: white; }
.nv2-flag-ph { background: linear-gradient(135deg, #0038a8 50%, #ce1126 50%); color: white; }
.nv2-flag-pk { background: linear-gradient(90deg, white 25%, #01411c 25%); color: #064e3b; }
.nv2-flag-ke { background: linear-gradient(180deg, #000 33.3%, #b00 33.3% 66.6%, #006600 66.6%); color: white; }
.nv2-flag-mx { background: linear-gradient(90deg, #006847 33.3%, white 33.3% 66.6%, #ce1126 66.6%); color: #1e293b; }
.nv2-flag-eg { background: linear-gradient(180deg, #ce1126 33.3%, white 33.3% 66.6%, #000 66.6%); color: white; }
.nv2-flag-bd { background: #006a4e; color: white; }
.nv2-flag-gh { background: linear-gradient(180deg, #ce1126 33.3%, #fcd116 33.3% 66.6%, #006b3f 66.6%); color: white; }
.nv2-flag-jp { background: white; color: #b00; position: relative; border: 1px solid var(--nv2-line); }

/* Stepper */
.nv2-stepper {
  display: flex; align-items: center;
  background: white;
  border: 1px solid var(--nv2-line);
  border-radius: var(--nv2-radius);
  padding: 14px 18px;
  margin-bottom: 22px;
}
.nv2-step { display: flex; align-items: center; gap: 10px; flex: 1; position: relative; }
.nv2-step:not(:last-child)::after {
  content: '';
  position: absolute;
  left: 32px; right: 0; top: 14px;
  height: 2px;
  background: var(--nv2-line);
  z-index: 0;
}
.nv2-step.is-complete:not(:last-child)::after { background: var(--nv2-ok); }
.nv2-step-number {
  width: 28px; height: 28px;
  border-radius: 50%;
  background: var(--nv2-bg);
  color: var(--nv2-ink-3);
  display: grid; place-items: center;
  font-family: var(--nv2-font-display); font-weight: 700; font-size: 13px;
  flex-shrink: 0;
  position: relative; z-index: 1;
  border: 2px solid var(--nv2-bg);
}
.nv2-step.is-active .nv2-step-number {
  background: var(--nv2-hub-accent, var(--nv2-brand));
  color: white;
  border-color: white;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--nv2-hub-accent, var(--nv2-brand)) 22%, transparent);
}
.nv2-step.is-complete .nv2-step-number { background: var(--nv2-ok); color: white; border-color: white; }
.nv2-step-text { font-size: 12.5px; }
.nv2-step-text strong {
  font-weight: 700;
  color: var(--nv2-ink-3);
  display: block;
  font-size: 9.5px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
.nv2-step.is-active .nv2-step-text strong { color: var(--nv2-hub-accent, var(--nv2-brand)); }
.nv2-step.is-complete .nv2-step-text strong { color: var(--nv2-ok); }
.nv2-step-text span { font-weight: 600; color: var(--nv2-ink); }

/* Toast stack — v2. ONE toast system, four severities, nothing hidden.
   The old stack was bottom-centre at z-index 2000 with pointer-events:none, so
   it sat UNDER the two fixed-top banners (z 9997/9998), the impersonation
   banner (z 9999) and the error pill (z 99997), collided with the copilot FAB
   at 390px, and could not be clicked, hovered or copied. White on
   var(--nv2-ok)/var(--nv2-danger) measured 2.5:1 and 3.8:1 — both below WCAG AA
   at 13px. The palette below is components/ui/Toast.jsx's (dark ink on a pale
   tint), which passes 4.5:1 at this size.
   `top` is set inline by <ToastStack> — 60px plus the measured height of
   whatever fixed banner is on screen — so the rule here is only the SSR floor. */
.nv2-toast-stack {
  position: fixed;
  top: 60px; left: 50%; transform: translateX(-50%);
  display: flex; flex-direction: column; gap: 8px;
  width: min(460px, calc(100vw - 32px));
  z-index: 100000;
  pointer-events: auto;
}
.nv2-toast {
  position: relative;
  background: white; color: var(--nv2-ink);
  padding: 10px 10px 10px 13px;
  border: 1px solid var(--nv2-line);
  border-left: 4px solid var(--nv2-ink-3);
  border-radius: 10px;
  font-size: 13px; font-weight: 500; line-height: 1.42;
  box-shadow: var(--nv2-shadow-lg);
  display: flex; align-items: flex-start; gap: 10px;
  pointer-events: auto;
  animation: nv2-toast-in 320ms cubic-bezier(0.16, 1, 0.3, 1);
}
.nv2-toast-success { background: #ecfdf5; color: #065f46; border-color: #a7f3d0; border-left-color: #10b981; }
.nv2-toast-info    { background: #eff6ff; color: #1e3a8a; border-color: #bfdbfe; border-left-color: #3b82f6; }
.nv2-toast-warning { background: #fffbeb; color: #92400e; border-color: #fde68a; border-left-color: #f59e0b; }
.nv2-toast-error   { background: #fef2f2; color: #991b1b; border-color: #fecaca; border-left-color: #ef4444; }
.nv2-toast svg { width: 16px; height: 16px; }
.nv2-toast-icon { flex: 0 0 auto; display: inline-flex; margin-top: 1px; }
.nv2-toast-body { flex: 1 1 auto; min-width: 0; }
.nv2-toast-label { font-weight: 700; margin-right: 6px; }
.nv2-toast-text { white-space: pre-wrap; overflow-wrap: anywhere; }
.nv2-toast-count {
  margin-left: 6px; padding: 0 5px;
  border-radius: 999px; background: rgba(15, 23, 42, 0.10);
  font-size: 11px; font-weight: 700; white-space: nowrap;
}
.nv2-toast-close {
  flex: 0 0 auto;
  width: 22px; height: 22px; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  background: transparent; border: none; border-radius: 6px;
  color: inherit; opacity: 0.65; cursor: pointer;
}
.nv2-toast-close:hover { opacity: 1; background: rgba(15, 23, 42, 0.08); }
.nv2-toast-close svg { width: 13px; height: 13px; }
.nv2-toast-more {
  align-self: center;
  padding: 4px 12px;
  border: 1px solid var(--nv2-line); border-radius: 999px;
  background: white; color: var(--nv2-ink-2);
  font-size: 11.5px; font-weight: 700; cursor: pointer;
  box-shadow: var(--nv2-shadow-lg);
  pointer-events: auto;
}
.nv2-toast-more:hover { color: var(--nv2-ink); }
@keyframes nv2-toast-in { from { opacity: 0; transform: translateY(-14px); } to { opacity: 1; transform: translateY(0); } }
/* 390px: full width under the topbar, above the hub drawer, clear of the FAB. */
@media (max-width: 600px) {
  .nv2-toast-stack { left: 8px; right: 8px; width: auto; transform: none; }
}

/* Empty state */
.nv2-empty-card {
  background: white;
  border: 1px dashed var(--nv2-line);
  border-radius: var(--nv2-radius);
  padding: 56px 24px;
  text-align: center;
  color: var(--nv2-ink-2);
}
.nv2-empty-card .nv2-empty-icon { font-size: 48px; opacity: 0.5; margin-bottom: 12px; }
.nv2-empty-card h3 { font-size: 16px; color: var(--nv2-ink); margin-bottom: 6px; }
.nv2-empty-card p { max-width: 380px; margin: 0 auto; font-size: 13px; }

/* Pager */
.nv2-pager { display: flex; gap: 4px; }
.nv2-pager button {
  width: 28px; height: 28px;
  border: 1px solid var(--nv2-line);
  background: white;
  border-radius: 6px;
  cursor: pointer;
  font-family: inherit; font-size: 12px; font-weight: 600;
  color: var(--nv2-ink-2);
  display: grid; place-items: center;
}
.nv2-pager button:hover:not(.is-active) { color: var(--nv2-brand); border-color: var(--nv2-brand); }
.nv2-pager button.is-active { background: var(--nv2-ink); color: white; border-color: var(--nv2-ink); }

/* ═══════════════════════════════════════════════════════════════════════════
   DATA — Tabs, Filters, Tables, Stat Cards
   ═══════════════════════════════════════════════════════════════════════════ */

/* Tab bar */
.nv2-tab-bar {
  display: flex; gap: 2px;
  border-bottom: 1px solid var(--nv2-line);
  margin-bottom: 22px;
  position: relative;
}
.nv2-tab {
  padding: 10px 16px;
  border: 0; background: transparent;
  font-family: inherit; font-size: 13px; font-weight: 600;
  color: var(--nv2-ink-2);
  cursor: pointer;
  position: relative;
  display: inline-flex; align-items: center; gap: 8px;
  border-radius: 8px 8px 0 0;
  transition: color 160ms ease, background 160ms ease;
}
.nv2-tab:hover { color: var(--nv2-ink); background: var(--nv2-panel-2); }
.nv2-tab.is-active {
  color: var(--nv2-hub-accent, var(--nv2-brand));
  /* Stronger selection cue — subtle tinted background plus the
     existing underline. The previous version relied on text-color +
     2px underline alone, which read as "hover" rather than "selected"
     to operators scanning the bar quickly. */
  background: color-mix(in srgb, var(--nv2-hub-accent, var(--nv2-brand)) 8%, transparent);
}
.nv2-tab.is-active::after {
  content: '';
  position: absolute;
  bottom: -1px; left: 8px; right: 8px;
  height: 3px;
  background: var(--nv2-hub-accent, var(--nv2-brand));
  border-radius: 3px 3px 0 0;
}
.nv2-tab-count {
  background: var(--nv2-bg-2);
  color: var(--nv2-ink-2);
  font-size: 11px; font-weight: 700;
  padding: 1px 7px;
  border-radius: 999px;
}
.nv2-tab.is-active .nv2-tab-count {
  background: color-mix(in srgb, var(--nv2-hub-accent, var(--nv2-brand)) 15%, white);
  color: var(--nv2-hub-accent, var(--nv2-brand));
}
/* Dense tab sets (Remittance 360): one row, horizontal scroll — prevents
   multi-line wrap that breaks tab height symmetry on laptop widths. */
.nv2-tab-bar.is-scroll {
  flex-wrap: nowrap;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
  gap: 0;
  margin-bottom: 16px;
}
.nv2-tab-bar.is-scroll .nv2-tab {
  flex-shrink: 0;
  white-space: nowrap;
  padding: 9px 14px;
  font-size: 12px;
}
.nv2-tab-bar.is-scroll::-webkit-scrollbar { height: 6px; }
.nv2-tab-bar.is-scroll::-webkit-scrollbar-thumb {
  background: var(--nv2-line);
  border-radius: 999px;
}
.nv2-tab-bar.is-scroll::-webkit-scrollbar-track { background: transparent; }

/* Remittance 360 layout — contained scroll, tab bar, readable panels */
.r360-page {
  display: flex;
  flex-direction: column;
  gap: 14px;
  max-width: 100%;
  overflow-x: hidden;
}
.r360-top {
  display: flex;
  flex-direction: column;
  gap: 12px;
  flex-shrink: 0;
}
.r360-summary {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 14px;
  padding: 12px 16px;
  background: var(--nv2-panel-2, #f8fafc);
  border: 1px solid var(--nv2-line, #e2e5ee);
  border-radius: var(--nv2-radius, 10px);
  font-size: 13px;
  line-height: 1.45;
  color: var(--nv2-ink-2);
}
.r360-summary-parties { font-weight: 600; color: var(--nv2-ink); }
.r360-summary-money { font-family: var(--nv2-font-mono); font-size: 12px; }
.r360-summary-sep { color: var(--nv2-ink-3); user-select: none; }
.r360-summary-meta { color: var(--nv2-ink-3); font-size: 12px; }
.r360-summary-back {
  margin-left: auto;
  color: var(--nv2-brand);
  font-weight: 600;
  white-space: nowrap;
  text-decoration: none;
}
.r360-summary-back:hover { text-decoration: underline; }

/* HTML mockup page header for Remittance 360 */
.r360-html-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  padding: 4px 0 2px;
}
.r360-html-head-main {
  min-width: 0;
  flex: 1 1 420px;
}
.r360-html-title-line {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
}
.r360-html-title {
  margin: 0;
  color: var(--nv2-ink);
  font-size: 1.5rem;
  font-weight: 800;
  line-height: 1.2;
}
.r360-html-status {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  border-radius: 999px;
  background: #ecfdf3;
  color: #067647;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}
.r360-html-status--held,
.r360-html-status--error { background: #fef2f2; color: #b42318; }
.r360-html-status--pending { background: #fff7ed; color: #c2410c; }
.r360-html-status--created { background: #eef2ff; color: #4338ca; }
.r360-html-status--paid,
.r360-html-status--confirmed,
.r360-html-status--checked { background: #ecfdf3; color: #067647; }
.r360-html-status-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
}
.r360-html-updated {
  color: var(--nv2-ink-3);
  font-size: 12px;
}
.r360-html-record {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 10px;
  color: var(--nv2-ink);
  font-size: 1.28rem;
  font-weight: 800;
  line-height: 1.2;
}
.r360-html-meta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px 14px;
  margin-top: 10px;
  color: var(--nv2-ink-2);
  font-size: 12px;
}
.r360-html-pill {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px 10px;
  border: 1px solid var(--nv2-line, #e2e5ee);
  border-radius: 999px;
  background: #fff;
}
.r360-html-actions {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  justify-content: flex-end;
}
.r360-html-owner {
  margin-right: 4px;
  color: var(--nv2-ink-2);
  font-size: 12px;
}
@media (max-width: 900px) {
  .r360-html-actions { justify-content: flex-start; width: 100%; }
}

.r360-dims {
  display: grid;
  grid-template-columns: repeat(9, minmax(0, 1fr));
  gap: 8px;
  width: 100%;
}
.r360-dim {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 6px;
  padding: 8px 8px 10px;
  background: #fff;
  border: 1px solid var(--nv2-line, #e2e5ee);
  border-radius: 8px;
  min-width: 0;
  overflow: visible;
}
.r360-dim-label {
  font-size: 9px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--nv2-ink-3);
  line-height: 1.2;
}
/* Status pills in dim cards — wrap long values (COMPLIANCE_CHECK_PENDING etc.) */
.r360-dim .nv2-pill {
  display: flex;
  align-items: flex-start;
  justify-content: flex-start;
  width: 100%;
  max-width: 100%;
  white-space: normal;
  word-break: break-word;
  overflow-wrap: anywhere;
  font-size: 9px;
  line-height: 1.25;
  padding: 4px 6px;
  border-radius: 6px;
  letter-spacing: 0.02em;
}
.r360-dim .nv2-pill::before {
  flex-shrink: 0;
  margin-top: 3px;
}
.r360-alert {
  padding: 8px 12px;
  border-radius: 8px;
  font-size: 12px;
  line-height: 1.4;
}
.r360-alert--warn {
  background: #fffbeb;
  border: 1px solid #fde68a;
  color: #92400e;
}
.r360-alert--error {
  background: #fef2f2;
  border: 1px solid #fecaca;
  color: #991b1b;
}
.r360-blockers { display: flex; flex-direction: column; gap: 8px; }
.r360-blocker {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px 8px;
  padding: 8px 12px;
  background: #fef2f2;
  border: 1px solid #fecaca;
  border-radius: 8px;
  font-size: 13px;
  color: #991b1b;
}
.r360-blocker-owner { color: var(--nv2-ink-3); }
.r360-blocker-link {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  color: var(--nv2-brand);
  white-space: nowrap;
}

/* Sticky tab strip — horizontal scroll only here, not whole page */
.r360-tabs-shell {
  position: sticky;
  top: 0;
  z-index: 6;
  flex-shrink: 0;
  width: 100%;
  max-width: 100%;
  overflow: hidden;
  margin: 0;
  padding: 0;
  background: var(--nv2-bg);
  border-bottom: 1px solid var(--nv2-line, #e2e5ee);
  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.04);
}
.r360-tabs-shell::before,
.r360-tabs-shell::after {
  content: '';
  position: absolute;
  top: 0;
  bottom: 8px;
  width: 18px;
  pointer-events: none;
  z-index: 2;
}
.r360-tabs-shell::before {
  left: 0;
  background: linear-gradient(to right, var(--nv2-bg) 30%, transparent);
}
.r360-tabs-shell::after {
  right: 0;
  background: linear-gradient(to left, var(--nv2-bg) 30%, transparent);
}
.r360-tabs-shell .nv2-tab-bar.r360-tab-bar.is-scroll {
  margin-bottom: 0;
  border-bottom: 0;
  overflow-x: auto;
  overflow-y: hidden;
  flex-wrap: nowrap;
  scrollbar-width: thin;
  scrollbar-color: var(--nv2-line) transparent;
  padding: 0 2px 4px;
  -webkit-overflow-scrolling: touch;
}
.r360-tabs-shell .nv2-tab-bar.is-scroll .nv2-tab {
  flex-shrink: 0;
  white-space: nowrap;
  padding: 10px 14px;
  font-size: 12px;
}
.r360-tabs-shell .nv2-tab-bar.is-scroll::-webkit-scrollbar { height: 7px; }
.r360-tabs-shell .nv2-tab-bar.is-scroll::-webkit-scrollbar-thumb {
  background: var(--nv2-line);
  border-radius: 999px;
}
.r360-tabs-shell .nv2-tab-bar.is-scroll::-webkit-scrollbar-thumb:hover {
  background: var(--nv2-ink-3);
}
.r360-tabs-shell .nv2-tab-bar.is-scroll::-webkit-scrollbar-track {
  background: var(--nv2-panel-2, #f1f5f9);
  border-radius: 999px;
}

/* Tab body — scrolls with main content pane */
.r360-tab-panel {
  overflow-x: hidden;
  padding: 14px 16px 18px;
  background: #fff;
  border: 1px solid var(--nv2-line, #e2e5ee);
  border-radius: 12px;
  scrollbar-width: thin;
  scrollbar-color: var(--nv2-line) transparent;
}
.r360-tab-panel::-webkit-scrollbar { width: 8px; }
.r360-tab-panel::-webkit-scrollbar-thumb {
  background: var(--nv2-line);
  border-radius: 999px;
}
.r360-tab-panel::-webkit-scrollbar-track { background: transparent; }
.r360-tab-panel.is-loading { opacity: 0.55; pointer-events: none; }
.r360-tab-loading {
  margin: 0;
  padding: 24px 0;
  text-align: center;
  font-size: 13px;
  color: var(--nv2-ink-3);
}

.r360-panels {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 12px;
  align-items: start;
}
.r360-panel {
  background: var(--nv2-panel-2, #f8fafc);
  border: 1px solid var(--nv2-line, #e2e5ee);
  border-radius: 10px;
  padding: 14px 16px;
  margin: 0;
  min-width: 0;
}
.r360-panel--wide { grid-column: 1 / -1; }
.r360-panel-title {
  font-size: 12px;
  font-weight: 700;
  margin: 0 0 10px;
  color: var(--nv2-ink-2);
  text-transform: uppercase;
  letter-spacing: 0.03em;
}
.r360-panel-note {
  grid-column: 1 / -1;
  display: flex;
  align-items: flex-start;
  gap: 6px;
  margin: 0;
  padding: 10px 12px;
  font-size: 12px;
  line-height: 1.45;
  color: var(--nv2-ink-3);
  background: var(--nv2-panel-2, #f8fafc);
  border: 1px solid var(--nv2-line, #e2e5ee);
  border-radius: 8px;
}
.r360-panel-note svg { flex-shrink: 0; margin-top: 2px; }
.r360-module-link {
  grid-column: 1 / -1;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  width: fit-content;
  margin-top: 2px;
}
.r360-dl {
  display: grid;
  grid-template-columns: 1fr;
  gap: 10px;
  margin: 0;
}
.r360-dl-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 2px;
  padding-bottom: 8px;
  border-bottom: 1px solid color-mix(in srgb, var(--nv2-line) 70%, transparent);
}
.r360-dl-row:last-child { padding-bottom: 0; border-bottom: 0; }
.r360-dl dt {
  font-size: 11px;
  font-weight: 600;
  color: var(--nv2-ink-3);
  margin: 0;
  line-height: 1.3;
}
.r360-dl dd {
  font-size: 13px;
  font-weight: 600;
  margin: 0;
  line-height: 1.4;
  word-break: break-word;
  color: var(--nv2-ink);
}
.r360-empty { margin: 0; font-size: 13px; color: var(--nv2-ink-3); }
.r360-timeline {
  margin: 0;
  padding-left: 18px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.r360-timeline li { font-size: 13px; line-height: 1.45; }
.r360-timeline-meta { color: var(--nv2-ink-3); }

/* Remittance 360 overview — integrated form of the approved container mockup. */
.r360-overview {
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.r360-ov-card {
  min-width: 0;
  overflow: hidden;
  background: #fff;
  border: 1px solid var(--nv2-line, #e2e5ee);
  border-radius: 11px;
  box-shadow: 0 3px 12px rgba(26, 42, 74, 0.035);
}
.r360-ov-card-title {
  margin: 0;
  padding: 14px 15px 8px;
  color: var(--nv2-ink);
  font-size: 13px;
  font-weight: 750;
  line-height: 1.35;
}
.r360-ov-money-grid {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  padding: 14px 0;
}
.r360-ov-money-item {
  display: flex;
  min-width: 0;
  min-height: 76px;
  flex-direction: column;
  justify-content: center;
  gap: 7px;
  padding: 3px 15px;
  border-right: 1px solid var(--nv2-line, #e2e5ee);
}
.r360-ov-money-item:last-child { border-right: 0; }
.r360-ov-money-item > span {
  color: var(--nv2-ink-3);
  font-size: 10px;
}
.r360-ov-money-item > strong {
  overflow-wrap: anywhere;
  color: var(--nv2-ink);
  font-size: 15px;
  font-weight: 750;
  line-height: 1.25;
}
.r360-ov-money-item > small {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  overflow-wrap: anywhere;
  color: var(--nv2-ink-3);
  font-size: 10px;
  line-height: 1.25;
}
.r360-ov-lifecycle {
  display: grid;
  grid-template-columns: repeat(8, minmax(86px, 1fr));
  padding: 8px 10px 16px;
}
.r360-ov-life-step {
  position: relative;
  display: flex;
  min-width: 0;
  flex-direction: column;
  align-items: center;
  padding: 0 4px;
  text-align: center;
}
.r360-ov-life-step::before {
  position: absolute;
  z-index: 0;
  top: 13px;
  left: -50%;
  width: 100%;
  height: 2px;
  background: #d7deea;
  content: '';
}
.r360-ov-life-step:first-child::before { display: none; }
.r360-ov-life-step.is-done::before,
.r360-ov-life-step.is-active::before { background: #33b77b; }
.r360-ov-life-dot {
  position: relative;
  z-index: 1;
  display: grid;
  width: 28px;
  height: 28px;
  margin-bottom: 7px;
  place-items: center;
  border: 4px solid #f7f9fc;
  border-radius: 50%;
  background: #eef2f7;
  color: #8a94a8;
}
.r360-ov-life-step.is-done .r360-ov-life-dot { background: #20b26b; color: #fff; }
.r360-ov-life-step.is-active .r360-ov-life-dot { background: var(--nv2-brand); color: #fff; }
.r360-ov-life-step > strong {
  color: var(--nv2-ink);
  font-size: 10px;
  line-height: 1.25;
}
.r360-ov-life-step > span:not(.r360-ov-life-dot) {
  margin-top: 3px;
  color: var(--nv2-ink-3);
  font-size: 9px;
  line-height: 1.25;
  text-transform: capitalize;
}
.r360-ov-life-step.is-done > span:not(.r360-ov-life-dot) { color: #10834f; }
.r360-ov-life-step.is-active > span:not(.r360-ov-life-dot) { color: var(--nv2-brand); font-weight: 700; }
.r360-ov-life-step > small {
  margin-top: 3px;
  color: var(--nv2-ink-3);
  font-size: 8px;
  line-height: 1.2;
}
.r360-ov-layout {
  display: grid;
  grid-template-columns: minmax(0, 3fr) minmax(230px, 1fr);
  gap: 14px;
  align-items: start;
}
.r360-ov-main,
.r360-ov-rail {
  display: flex;
  min-width: 0;
  flex-direction: column;
  gap: 14px;
}
.r360-ov-two-col {
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(260px, 5fr);
  gap: 14px;
}
.r360-ov-summary-columns {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px;
  padding: 8px 15px 15px;
}
.r360-ov-summary-list {
  display: flex;
  flex-direction: column;
  gap: 9px;
  margin: 0;
}
.r360-ov-summary-row {
  display: grid;
  grid-template-columns: minmax(90px, 42%) minmax(0, 1fr);
  gap: 8px;
  font-size: 10px;
  line-height: 1.35;
}
.r360-ov-summary-row dt { color: var(--nv2-ink-3); font-weight: 500; }
.r360-ov-summary-row dd {
  min-width: 0;
  margin: 0;
  overflow-wrap: anywhere;
  color: var(--nv2-ink);
  font-weight: 650;
}
.r360-ov-summary-row a,
.r360-ov-table a { color: var(--nv2-brand); text-decoration: none; }
.r360-ov-summary-row a:hover,
.r360-ov-table a:hover { text-decoration: underline; }
.r360-ov-financial {
  display: flex;
  flex-direction: column;
  gap: 9px;
  padding: 8px 15px 15px;
}
.r360-ov-financial-row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 10px;
  color: var(--nv2-ink-2);
  font-size: 10px;
}
.r360-ov-financial-row strong { color: var(--nv2-ink); text-align: right; }
.r360-ov-financial-row.is-total {
  margin-top: 2px;
  padding-top: 9px;
  border-top: 1px solid var(--nv2-line);
  font-weight: 750;
}
.r360-ov-text-link {
  display: inline-flex;
  width: fit-content;
  align-items: center;
  gap: 4px;
  margin-top: 3px;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--nv2-brand);
  font: inherit;
  font-size: 10px;
  font-weight: 700;
  cursor: pointer;
}
.r360-ov-table-wrap { width: 100%; overflow-x: auto; }
.r360-ov-table {
  width: 100%;
  border-collapse: collapse;
  color: var(--nv2-ink-2);
  font-size: 10px;
}
.r360-ov-table th,
.r360-ov-table td {
  padding: 10px 12px;
  border-top: 1px solid #edf0f5;
  text-align: left;
  vertical-align: middle;
}
.r360-ov-table th {
  color: var(--nv2-ink-3);
  font-size: 9px;
  font-weight: 750;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  white-space: nowrap;
}
.r360-ov-table td:last-child a { display: inline-flex; align-items: center; gap: 4px; white-space: nowrap; }
.r360-ov-badge {
  display: inline-flex;
  max-width: 130px;
  align-items: center;
  padding: 3px 6px;
  overflow-wrap: anywhere;
  border-radius: 999px;
  font-size: 8px;
  font-weight: 750;
  line-height: 1.2;
}
.r360-ov-badge.is-danger { background: #fee2e2; color: #b42318; }
.r360-ov-badge.is-warning { background: #fef3c7; color: #92400e; }
.r360-ov-badge.is-info { background: #e0e7ff; color: #3730a3; }
.r360-ov-alert-item,
.r360-ov-case {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  margin: 0 12px;
  padding: 10px 2px;
  border-bottom: 1px solid #edf0f5;
  color: var(--nv2-ink);
  text-decoration: none;
}
.r360-ov-alert-item > span:nth-child(2),
.r360-ov-case > span:first-child {
  display: flex;
  min-width: 0;
  flex: 1;
  flex-direction: column;
  gap: 3px;
}
.r360-ov-alert-item strong,
.r360-ov-case strong { overflow-wrap: anywhere; font-size: 10px; line-height: 1.3; }
.r360-ov-alert-item small,
.r360-ov-case small { overflow-wrap: anywhere; color: var(--nv2-ink-3); font-size: 9px; line-height: 1.3; }
.r360-ov-alert-icon {
  display: grid;
  width: 24px;
  height: 24px;
  flex: 0 0 auto;
  place-items: center;
  border-radius: 7px;
  background: #fef2f2;
  color: #dc2626;
}
.r360-ov-action {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 14px;
  padding: 9px 0;
  border-bottom: 1px solid #edf0f5;
  color: var(--nv2-ink);
  font-size: 10px;
  text-decoration: none;
}
.r360-ov-action.is-danger { color: #b42318; }
.r360-ov-section-link {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin: 11px 14px 13px;
  color: var(--nv2-brand);
  font-size: 10px;
  font-weight: 700;
  text-decoration: none;
}
.r360-ov-empty {
  margin: 0;
  padding: 10px 15px 15px;
  color: var(--nv2-ink-3);
  font-size: 10px;
}

@media (max-width: 1280px) {
  .r360-dims {
    display: flex;
    flex-wrap: nowrap;
    overflow-x: auto;
    gap: 8px;
    padding-bottom: 4px;
    scrollbar-width: thin;
    -webkit-overflow-scrolling: touch;
  }
  .r360-dims::-webkit-scrollbar { height: 6px; }
  .r360-dims::-webkit-scrollbar-thumb {
    background: var(--nv2-line);
    border-radius: 999px;
  }
  .r360-dim {
    flex: 0 0 136px;
    min-width: 136px;
  }
  .r360-ov-money-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .r360-ov-money-item { border-right: 0; border-bottom: 1px solid var(--nv2-line); padding: 12px 15px; }
  .r360-ov-money-item:nth-child(odd) { border-right: 1px solid var(--nv2-line); }
  .r360-ov-money-item:last-child { grid-column: 1 / -1; border-bottom: 0; border-right: 0; }
  .r360-ov-lifecycle { grid-template-columns: repeat(4, minmax(86px, 1fr)); row-gap: 16px; }
  .r360-ov-life-step:nth-child(5)::before { display: none; }
  .r360-ov-layout { grid-template-columns: 1fr; }
  .r360-ov-rail { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); align-items: start; }
}
@media (min-width: 900px) {
  .r360-dl {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px 20px;
  }
  .r360-dl-row {
    border-bottom: 0;
    padding-bottom: 0;
  }
}
@media (max-width: 900px) {
  .r360-panels { grid-template-columns: 1fr; }
  .r360-ov-two-col { grid-template-columns: 1fr; }
  .r360-ov-rail { grid-template-columns: 1fr; }
}
@media (max-width: 640px) {
  .r360-summary-back { margin-left: 0; width: 100%; }
  .r360-dim { flex: 0 0 124px; min-width: 124px; }
  .r360-tabs-shell .nv2-tab-bar.is-scroll .nv2-tab {
    padding: 9px 11px;
    font-size: 11px;
  }
  .r360-tab-panel { padding: 10px; }
  .r360-ov-money-grid { grid-template-columns: 1fr; }
  .r360-ov-money-item,
  .r360-ov-money-item:nth-child(odd) { grid-column: auto; border-right: 0; border-bottom: 1px solid var(--nv2-line); }
  .r360-ov-money-item:last-child { grid-column: auto; }
  .r360-ov-lifecycle { grid-template-columns: repeat(2, minmax(86px, 1fr)); }
  .r360-ov-life-step:nth-child(odd)::before { display: none; }
  .r360-ov-summary-columns { grid-template-columns: 1fr; }
}

/* Filter bar */
.nv2-filter-bar {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  margin-bottom: 14px;
}
/* NPN-REMIT-FILTER-ONE-LINE (2026-06-05): status pill row on the ledger
   must stay on a single scannable line. Wrapping pushed "Held" onto a
   second row on laptop widths; nowrap + horizontal scroll keeps every chip
   reachable without breaking the mockup's one-row layout. */
.nv2-filter-bar.is-nowrap {
  flex-wrap: nowrap;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
  padding-bottom: 2px;
}
.nv2-filter-bar.is-nowrap .nv2-chip {
  flex-shrink: 0;
  white-space: nowrap;
}
.nv2-filter-bar.is-nowrap::-webkit-scrollbar { height: 6px; }
.nv2-filter-bar.is-nowrap::-webkit-scrollbar-thumb {
  background: var(--nv2-line);
  border-radius: 999px;
}
.nv2-filter-bar.is-nowrap::-webkit-scrollbar-thumb:hover { background: var(--nv2-ink-3); }
.nv2-filter-bar.is-nowrap::-webkit-scrollbar-track { background: transparent; }

/* NPN-REMIT-LIST-MOCKUP-STACK (2026-06-01): combined toolbar row used
   on the /remittance ledger — tabs sit on the left, debounced search
   fills the middle, filter-select chips + advanced-search icon hug the
   right. Suppresses the TabBar's own margin-bottom and the DebouncedSearch
   wrapper's inline margin-bottom so the row reads as one toolbar instead
   of three stacked components. */
.nv2-list-toolbar {
  display: flex; align-items: center; gap: 8px;
  margin-bottom: 14px;
  /* NPN-REMIT-LIST-SEARCH-FIX (2026-06-01): wrap by default. The previous
     `nowrap` crushed the search box down to a sliver whenever the tabs +
     three filter selects + advanced-search icon couldn't all fit on one
     line (any laptop/tablet width with the sidebar open). Wrapping lets the
     filter controls flow to a second line while the search keeps a usable
     width (see `.nv2-list-toolbar-grow` min-width below). */
  flex-wrap: wrap;
  min-width: 0;
}
.nv2-list-toolbar > .nv2-tab-bar {
  margin-bottom: 0;
  border-bottom: 0;
  flex: 0 0 auto;
  gap: 4px;
  padding: 2px;
  background: transparent;
}
/* NPN-REMIT-LIST-MOCKUP-2 (2026-06-01): tabs inside the toolbar use the
   dark-pill active style from the mockup, not the underline+tinted style
   the standalone TabBar uses. */
.nv2-list-toolbar > .nv2-tab-bar .nv2-tab {
  padding: 6px 12px;
  border-radius: 999px;
}
.nv2-list-toolbar > .nv2-tab-bar .nv2-tab.is-active {
  background: var(--nv2-ink);
  color: white;
}
.nv2-list-toolbar > .nv2-tab-bar .nv2-tab.is-active::after { display: none; }
.nv2-list-toolbar > .nv2-tab-bar .nv2-tab.is-active .nv2-tab-count {
  background: color-mix(in srgb, white 18%, transparent);
  color: white;
}
.nv2-list-toolbar-grow {
  /* Keep the search box from collapsing to a sliver between the tab bar and
     the filter chips. min-width forces it to wrap onto its own line (taking
     the chips with it) rather than shrinking to nothing on tight widths. */
  flex: 1 1 240px; min-width: 240px;
}
/* DebouncedSearch's root has an inline marginBottom:10 — kill it only
   when it lives inside the toolbar (other consumers keep the gap). */
.nv2-list-toolbar-grow > div { margin-bottom: 0 !important; }

/* Inline filter chip rendered INSIDE the toolbar search input via the
   DebouncedSearch `rightSlot` prop. Mockup pattern — when a corridor
   (or other dimension) is active, it surfaces as a removable pill
   sitting at the right edge of the search box, before the clear-X. */
.nv2-search-chip {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 4px 2px 9px;
  background: var(--nv2-bg-2, #f3f4f6);
  border: 1px solid var(--nv2-line);
  border-radius: 999px;
  font-size: 11.5px; font-weight: 600;
  color: var(--nv2-ink-2);
  white-space: nowrap;
}
.nv2-search-chip button {
  border: 0; background: transparent; cursor: pointer;
  width: 16px; height: 16px;
  border-radius: 50%;
  display: grid; place-items: center;
  color: var(--nv2-ink-3); padding: 0;
}
.nv2-search-chip button:hover { background: var(--nv2-line); color: var(--nv2-ink); }

/* NPN-REMIT-LIST-ROW-MENU (2026-06-01, updated): per-row 3-dot menu.
   Popover is position:fixed (coords set inline at open time) so the
   table's overflow-x:auto container can't clip it. Width 180px so
   "Print receipt" doesn't run two lines. The first danger item gets
   a top divider so destructive choices read as separate from safe
   ones. Small scale-in entrance keeps it feeling responsive. */
.nv2-row-menu-pop {
  width: 180px;
  background: white;
  border: 1px solid var(--nv2-line);
  border-radius: 10px;
  box-shadow: 0 12px 32px rgba(15, 23, 42, .18), 0 2px 6px rgba(15, 23, 42, .08);
  padding: 6px;
  z-index: 1000;
  animation: nv2-row-menu-in 120ms ease-out;
  transform-origin: top right;
}
@keyframes nv2-row-menu-in {
  from { opacity: 0; transform: translateY(-4px) scale(0.96); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
.nv2-row-menu-item {
  display: flex; align-items: center; gap: 10px;
  width: 100%;
  border: 0; background: transparent;
  padding: 8px 10px;
  border-radius: 6px;
  font-size: 13px; font-weight: 500;
  color: var(--nv2-ink);
  text-align: left;
  cursor: pointer;
  font-family: inherit;
  transition: background .12s ease, color .12s ease;
}
.nv2-row-menu-item:hover { background: var(--nv2-bg-2, #f3f4f6); }
.nv2-row-menu-item:disabled { opacity: .45; cursor: not-allowed; }
.nv2-row-menu-item:disabled:hover { background: transparent; }
.nv2-row-menu-item.is-danger { color: var(--nv2-danger, #dc2626); }
.nv2-row-menu-item.is-danger:hover { background: color-mix(in srgb, var(--nv2-danger, #dc2626) 8%, white); }
.nv2-row-menu-item.is-danger:not(:first-child) {
  margin-top: 4px; padding-top: 10px;
  border-top: 1px solid var(--nv2-line);
}
.nv2-row-menu-item > svg { flex-shrink: 0; color: currentColor; width: 14px; height: 14px; }
.nv2-chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 11px;
  background: white;
  border: 1px solid var(--nv2-line);
  border-radius: 999px;
  font-size: 12px; font-weight: 600;
  color: var(--nv2-ink-2);
  cursor: pointer;
  transition: all 140ms ease;
  font-family: inherit;
}
.nv2-chip:hover { border-color: var(--nv2-ink-3); color: var(--nv2-ink); }
.nv2-chip.is-active {
  background: var(--nv2-ink);
  color: white;
  border-color: var(--nv2-ink);
  box-shadow: 0 1px 3px rgba(15, 23, 42, .18);
}
.nv2-chip.is-active svg { color: white; }
.nv2-chip-count { margin-left: 6px; font-weight: 600; opacity: 0.7; }
.nv2-chip.is-active .nv2-chip-count { opacity: 0.92; }
.nv2-chip svg { width: 11px; height: 11px; }
.nv2-chip-divider { width: 1px; height: 18px; background: var(--nv2-line); margin: 0 4px; }
/* NPN-REMIT-STATUS-MORE (2026-06-05): overflow status filters. */
.nv2-chip-more { flex-shrink: 0; white-space: nowrap; }
.nv2-status-more-pop { width: 240px; }
.nv2-status-more-item.is-active {
  background: color-mix(in srgb, var(--nv2-ink) 8%, white);
  font-weight: 600;
}
.nv2-status-more-count {
  font-size: 11.5px;
  font-weight: 600;
  color: var(--nv2-ink-3);
  margin-left: 8px;
}
.nv2-status-more-item.is-active .nv2-status-more-count { color: var(--nv2-ink-2); }

/* Stat card */
.nv2-stats-grid { display: grid; gap: 18px; margin-bottom: 22px; }
.nv2-stats-grid-3 { grid-template-columns: repeat(3, 1fr); }
.nv2-stats-grid-4 { grid-template-columns: repeat(4, 1fr); }
/* NPN-REMIT-LIST-LEDGER-LOOK (2026-05-26): 5-column variant for the
   /remittance ALL-tab KPI strip (mockup shows All / In flight / Pending
   / Errored / Volume in one horizontal row). Without this rule the
   `nv2-stats-grid-5` class hit the no-template fallback and stacked
   the cards vertically. */
.nv2-stats-grid-5 { grid-template-columns: repeat(5, 1fr); }
/* NPN-REMIT-LIST-SETTLED-KPI (2026-06-01): 6-column variant for the
   /remittance ALL-tab KPI strip once the Settled card is added
   (All / In flight / Pending / Errored / Settled / Volume). */
.nv2-stats-grid-6 { grid-template-columns: repeat(6, 1fr); }

/* NPN-REMIT-KPI-ONE-LINE (2026-06-05): the ledger's connected 6-card
   ribbon must stay on a single row. Horizontal scroll on narrow widths
   beats wrapping Settled / Volume onto a second line. */
.nv2-stats-grid-tight.nv2-stats-grid-6 {
  grid-template-columns: repeat(6, minmax(0, 1fr));
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
}
.nv2-stats-grid-tight.nv2-stats-grid-6 .nv2-stat-card {
  min-width: 130px;
}
/* Action Centre KPI ribbon dropped to 5 cards (Waiting Ext moved to the
   chip row); same one-row / horizontal-scroll behaviour as the 6/8 tight
   ribbons so it never wraps on narrow widths. */
.nv2-stats-grid-tight.nv2-stats-grid-5 {
  grid-template-columns: repeat(5, minmax(0, 1fr));
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
}
.nv2-stats-grid-tight.nv2-stats-grid-5 .nv2-stat-card {
  min-width: 140px;
}
.nv2-stats-grid-tight.nv2-stats-grid-5::-webkit-scrollbar { height: 6px; }
.nv2-stats-grid-tight.nv2-stats-grid-5::-webkit-scrollbar-thumb {
  background: var(--nv2-line);
  border-radius: 999px;
}
/* RAC (Action Centre spec §4.1): the queue page carries an 8-card KPI strip
   (Open … Reopened) in the same connected-ribbon style as the ledger's 6. */
.nv2-stats-grid-8 { grid-template-columns: repeat(8, 1fr); }
.nv2-stats-grid-tight.nv2-stats-grid-8 {
  grid-template-columns: repeat(8, minmax(0, 1fr));
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.nv2-stats-grid-tight.nv2-stats-grid-8 .nv2-stat-card {
  min-width: 118px;
}
.nv2-stats-grid-tight.nv2-stats-grid-8::-webkit-scrollbar { height: 6px; }
.nv2-stats-grid-tight.nv2-stats-grid-8::-webkit-scrollbar-thumb {
  background: var(--nv2-line);
  border-radius: 999px;
}
.nv2-stats-grid-tight.nv2-stats-grid-6::-webkit-scrollbar { height: 6px; }
.nv2-stats-grid-tight.nv2-stats-grid-6::-webkit-scrollbar-thumb {
  background: var(--nv2-line);
  border-radius: 999px;
}

/* NPN-REMIT-LIST-RESPONSIVE (2026-06-01): collapse wide *gapped* grids on
   narrow viewports. The tight ledger ribbon is excluded — see rule above. */
@media (max-width: 1280px) {
  .nv2-stats-grid-5,
  .nv2-stats-grid-6:not(.nv2-stats-grid-tight) { grid-template-columns: repeat(3, 1fr); }
}
@media (max-width: 900px) {
  .nv2-stats-grid-4,
  .nv2-stats-grid-5,
  .nv2-stats-grid-6:not(.nv2-stats-grid-tight) { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 540px) {
  .nv2-stats-grid-3,
  .nv2-stats-grid-4,
  .nv2-stats-grid-5,
  .nv2-stats-grid-6:not(.nv2-stats-grid-tight) { grid-template-columns: 1fr; }
}

/* D34-V2-02 (deploy #34 verifier 2, 2026-09-05): THE TIGHT RIBBON HAD NO WIDTH
   ANSWER BELOW 540px, AND THE COLLAPSE ABOVE CANNOT BE THE ONE.
   Measured in Chromium at 390x844 on /remittance?tab=all for SUPER_ADMIN and
   TELLER: five leaves inside .nv2-stats-grid-tight overflowed their own boxes —
   four labels ("All Transactions" 95px in 50, "Created/Pending" 114 in 49,
   "Failed & Rejected" 61 in 49, "Compliance review" 79 in 49) AND THE MONEY
   VALUE (£16.5K, 74px in 49). text-overflow is `clip` by default here, so
   nothing signals it: a figure reading "£16." and one reading "£16.5K" are
   indistinguishable on the screen.
   The arithmetic: six repeat(6, minmax(0,1fr)) tracks in ~356px of content box
   give ~59px each; the card's min-width:130px then wins, and inside those 130px
   the has-side-icon row spends 32px of padding, a 32px icon and a 12px gap —
   leaving the label/value body about 49px.
   WHY NOT SIMPLY DROP THE `:not(.nv2-stats-grid-tight)` ABOVE: that rule is
   `.nv2-stats-grid-6` (0,1,0) while the ribbon's own template is
   `.nv2-stats-grid-tight.nv2-stats-grid-6` (0,2,0). A media query adds no
   specificity, so removing the :not() changes nothing at all — the fix has to
   match the ribbon's own specificity, which is what these rules do.
   WHAT THIS DOES: the ribbon already scrolls horizontally by design ("horizontal
   scroll on narrow widths beats wrapping" — NPN-REMIT-KPI-ONE-LINE). The missing
   half was tracks sized to their CONTENT instead of to a container too narrow to
   hold them. max-content tracks plus a max-content floor on the body give every
   tile exactly the width its own label and value need; the operator scrolls the
   ribbon to reach the later tiles and no text is ever cut. Nothing changes above
   540px. Pinned by tests/d34v2-02-kpi-ribbon-390.test.js. */
@media (max-width: 540px) {
  .nv2-stats-grid-tight.nv2-stats-grid-5 { grid-template-columns: repeat(5, max-content); }
  .nv2-stats-grid-tight.nv2-stats-grid-6 { grid-template-columns: repeat(6, max-content); }
  .nv2-stats-grid-tight.nv2-stats-grid-8 { grid-template-columns: repeat(8, max-content); }
  .nv2-stats-grid-tight .nv2-stat-card.has-side-icon .nv2-stat-body { min-width: max-content; }
}
.nv2-stat-card {
  background: white;
  border: 1px solid var(--nv2-line);
  border-radius: var(--nv2-radius);
  padding: 16px 18px;
  position: relative;
  transition: transform 200ms ease, box-shadow 200ms ease;
}
.nv2-stat-card:hover { transform: translateY(-2px); box-shadow: var(--nv2-shadow-md); }
.nv2-stat-card .nv2-stat-label {
  font-size: 11px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--nv2-ink-3);
}
.nv2-stat-card .nv2-stat-value {
  font-family: var(--nv2-font-display);
  font-size: 28px; font-weight: 700;
  margin-top: 4px;
  color: var(--nv2-ink);
  line-height: 1.1;
}
.nv2-stat-card .nv2-stat-delta {
  font-size: 12px; font-weight: 600; margin-top: 6px;
  display: inline-flex; align-items: center; gap: 3px;
}
.nv2-stat-card .nv2-stat-delta.is-up { color: var(--nv2-ok); }
.nv2-stat-card .nv2-stat-delta.is-down { color: var(--nv2-accent); }
.nv2-stat-card .nv2-stat-delta.is-neutral { color: var(--nv2-ink-3); }
.nv2-stat-card .nv2-stat-icon-bg {
  position: absolute; top: 16px; right: 16px;
  width: 34px; height: 34px;
  border-radius: 8px;
  display: grid; place-items: center;
}

/* NPN-REMIT-LIST-MOCKUP-2 (2026-06-01): icon-on-left tile layout.
   `.has-side-icon` becomes a 3-cell flex row — icon, body (label+value),
   delta right-aligned. The .nv2-stat-icon-side renders the icon as a
   small tinted square instead of an absolute floating chip. */
.nv2-stat-card.has-side-icon {
  display: flex; align-items: center; gap: 12px;
  padding: 14px 16px;
  position: relative;
}
.nv2-stat-card.has-side-icon .nv2-stat-icon-side {
  width: 32px; height: 32px; border-radius: 8px;
  display: grid; place-items: center; flex-shrink: 0;
}
.nv2-stat-card.has-side-icon .nv2-stat-body { flex: 1; min-width: 0; }
.nv2-stat-card.has-side-icon .nv2-stat-label { margin-bottom: 1px; }
.nv2-stat-card.has-side-icon .nv2-stat-value { font-size: 22px; margin-top: 2px; }
/* NZ8-147 (FIX-29, 2026-09-12): above 540px the tight ribbon's tracks are minmax(0,1fr) and the
   body inside a 142-157px card is 61-77px wide (measured on staging at 1280/1366), while a seven-
   character figure at 22px needs ~95px - so "VOLUME . 24H GBP 500.00" was cut by its own card. The
   body is the size container and the figure is sized from the body's own width, never clipped.
   Below 540px nothing changes: the max-content floor above stays as d34v2-02 pins it. */
@media (min-width: 541px) {
  .nv2-stat-card.has-side-icon .nv2-stat-body { container-type: inline-size; }
  .nv2-stat-card.has-side-icon .nv2-stat-value { font-size: clamp(12px, 23cqw, 22px); white-space: nowrap; }
}
.nv2-stat-card.has-side-icon .nv2-stat-delta { margin-top: 0; flex-shrink: 0; font-size: 11.5px; }

/* NPN-REMIT-LIST-KPI-STRIP (2026-06-01): "tight" variant collapses the
   inter-card gutter and rebrands the row as one connected strip with
   thin internal dividers. The mockup KPI bar reads as a single ribbon,
   not five disconnected cards. Scoped via the modifier class so default
   StatsGrid usage on other pages is untouched. */
.nv2-stats-grid-tight {
  gap: 0;
  background: white;
  border: 1px solid var(--nv2-line);
  border-radius: var(--nv2-radius);
  overflow: hidden;
  box-shadow: var(--nv2-shadow-sm, 0 1px 2px rgba(15,20,30,.04));
}
.nv2-stats-grid-tight .nv2-stat-card {
  background: transparent;
  border: 0;
  border-left: 1px solid var(--nv2-line);
  border-radius: 0;
  padding: 14px 18px;
}
.nv2-stats-grid-tight .nv2-stat-card:first-child { border-left: 0; }
/* The lift-on-hover would look broken inside a flush ribbon — neutralise
   it without disabling hover on the rest of the design system. */
.nv2-stats-grid-tight .nv2-stat-card:hover { transform: none; box-shadow: none; }
/* Top dividers only when a tight grid actually wraps (non-ledger consumers).
   The ledger 6-card ribbon stays one row — no row-wrap dividers needed. */
@media (max-width: 1280px) {
  .nv2-stats-grid-tight:not(.nv2-stats-grid-6) .nv2-stat-card { border-top: 1px solid var(--nv2-line); }
}

/* Hero KPI */
.nv2-hero {
  background: linear-gradient(135deg, var(--nv2-rail) 0%, var(--nv2-rail-2) 100%);
  color: white;
  border-radius: var(--nv2-radius-lg);
  padding: 26px 28px;
  margin-bottom: 18px;
  position: relative;
  overflow: hidden;
}
.nv2-hero::after {
  content: '';
  position: absolute;
  top: -100px; right: -100px;
  width: 300px; height: 300px;
  background: radial-gradient(circle, color-mix(in srgb, var(--nv2-hub-accent, var(--nv2-brand)) 25%, transparent) 0%, transparent 70%);
  pointer-events: none;
}
.nv2-hero-grid {
  display: grid; grid-template-columns: 2fr 3fr; gap: 32px;
  position: relative; z-index: 1;
}
.nv2-hero-label {
  font-size: 11px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.10em;
  color: rgba(255,255,255,0.6);
}
.nv2-hero-value {
  font-family: var(--nv2-font-display);
  font-size: 44px; font-weight: 800;
  margin-top: 6px; line-height: 1;
  letter-spacing: -0.02em;
}
.nv2-hero-delta {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 12.5px; font-weight: 700;
  margin-top: 10px;
  padding: 4px 10px;
  background: rgba(16, 185, 129, 0.18);
  color: #6ee7b7;
  border-radius: 999px;
}
.nv2-hero-delta.is-down { background: rgba(239, 68, 68, 0.18); color: #fca5a5; }
.nv2-hero-context { font-size: 12.5px; color: rgba(255,255,255,0.65); margin-top: 12px; }
.nv2-hero-mini-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; align-self: center; }
.nv2-hero-mini { background: rgba(255,255,255,0.06); border-radius: 10px; padding: 12px 14px; }
.nv2-hero-mini-label { font-size: 10.5px; font-weight: 700; text-transform: uppercase; color: rgba(255,255,255,0.5); letter-spacing: 0.08em; }
.nv2-hero-mini-val { font-family: var(--nv2-font-display); font-size: 19px; font-weight: 700; margin-top: 4px; }
.nv2-hero-mini-d { font-size: 11px; color: #6ee7b7; margin-top: 2px; }
.nv2-hero-mini-d.is-down { color: #fca5a5; }

/* Tables */
.nv2-table-card {
  background: white;
  border: 1px solid var(--nv2-line);
  border-radius: var(--nv2-radius);
  overflow: hidden;
  box-shadow: var(--nv2-shadow-xs);
}
.nv2-table-toolbar {
  display: flex; align-items: center; justify-content: space-between;
  padding: 12px 16px;
  border-bottom: 1px solid var(--nv2-line-2);
  background: var(--nv2-panel-2);
  font-size: 12.5px;
  color: var(--nv2-ink-2);
}
.nv2-table-toolbar-left { display: flex; align-items: center; gap: 10px; }
.nv2-table-toolbar-right { display: flex; align-items: center; gap: 6px; }
.nv2-bulk-bar {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 16px;
  background: linear-gradient(90deg, var(--nv2-brand-soft) 0%, color-mix(in srgb, var(--nv2-accent) 8%, white) 100%);
  border-bottom: 1px solid var(--nv2-line-2);
  font-size: 12.5px; font-weight: 600;
  color: var(--nv2-brand);
}
.nv2-bulk-bar-actions { margin-left: auto; display: flex; gap: 6px; }

/* Horizontal-scroll wrapper so wide tables don't squash columns or
   overflow the card on small / tablet viewports. The card keeps
   overflow:hidden for rounded corners; this wrapper provides the
   scroll container. */
.nv2-table-scroll {
  overflow-x: auto;
  overflow-y: visible;
  -webkit-overflow-scrolling: touch;
}
/* NPN-REMIT-LIST-ROW-MENU (2026-06-01): bump min-width so the actions
   column never gets squeezed off the right edge — when columns would
   otherwise fit tightly, the right-most Action cell was being clipped
   under the card border. With 1280px the scroll bar appears
   immediately at narrower viewports, signaling "more content right". */
.nv2-table { width: 100%; min-width: 1280px; border-collapse: collapse; }
/* Visible scrollbar (Chromium / WebKit) so operators see the affordance
   without needing to overscroll. Firefox uses its own thin native bar
   which is already discoverable. */
.nv2-table-scroll::-webkit-scrollbar { height: 10px; }
.nv2-table-scroll::-webkit-scrollbar-thumb {
  background: var(--nv2-line);
  border-radius: 999px;
  border: 2px solid var(--nv2-panel-2);
}
.nv2-table-scroll::-webkit-scrollbar-thumb:hover { background: var(--nv2-ink-3); }
.nv2-table-scroll::-webkit-scrollbar-track { background: var(--nv2-panel-2); }
/* Keep content on a single line so columns don't auto-squeeze; the
   nv2-table-scroll wrapper handles the overflow. Cells that legitimately
   want to wrap can opt in via cellClass="is-wrap". */
.nv2-table th,
.nv2-table td { white-space: nowrap; }
.nv2-table td.is-wrap { white-space: normal; }
.nv2-table thead th {
  text-align: left;
  padding: 10px 16px;
  font-size: 10.5px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--nv2-ink-3);
  background: var(--nv2-panel-2);
  border-bottom: 1px solid var(--nv2-line);
  white-space: nowrap;
}
.nv2-table thead th.is-num { text-align: right; }
.nv2-table thead th.is-checkbox { width: 36px; }
.nv2-table tbody tr { border-bottom: 1px solid var(--nv2-line-2); transition: background 120ms ease; }
.nv2-table tbody tr:hover { background: var(--nv2-panel-2); }
.nv2-table tbody tr.is-selected { background: color-mix(in srgb, var(--nv2-hub-accent, var(--nv2-brand)) 5%, white); }
.nv2-table tbody td { padding: 12px 16px; font-size: 13px; vertical-align: middle; }
.nv2-table td.is-id { font-family: var(--nv2-font-display); font-weight: 700; color: var(--nv2-ink); }
.nv2-table td.is-num {
  text-align: right;
  font-family: var(--nv2-font-mono);
  font-weight: 700;
  color: var(--nv2-ink);
}
.nv2-table-footer {
  display: flex; align-items: center; justify-content: space-between;
  padding: 10px 16px;
  background: var(--nv2-panel-2);
  border-top: 1px solid var(--nv2-line-2);
  font-size: 12px; color: var(--nv2-ink-2);
}
.nv2-row-actions { display: inline-flex; gap: 2px; }
/* NPN-REMIT-LIST-ROW-MENU-FIX (2026-06-01): use direct-child selector
   (`> button`, `> a`) so the row-menu popover (rendered as a sibling
   in the React tree but a descendant in the DOM tree) doesn't inherit
   the 28x28-square chip styling and collapse its 180px-wide menu
   items into tiny boxes. */
.nv2-row-actions > button,
.nv2-row-actions > a {
  width: 28px; height: 28px;
  border: 0; background: transparent;
  border-radius: 6px;
  /* NPN-REMIT-LIST-ACTION-CONTRAST (2026-06-01): was --nv2-ink-3 (#94a3b8),
     which rendered the Open / more-actions icons near-invisible on white.
     Use the mid ink so the affordances are clearly visible at rest. */
  color: var(--nv2-ink-2);
  cursor: pointer;
  display: grid; place-items: center;
  transition: all 120ms ease;
}
.nv2-row-actions > button:hover,
.nv2-row-actions > a:hover { background: white; color: var(--nv2-brand); box-shadow: var(--nv2-shadow-xs); }
.nv2-row-actions > button > svg,
.nv2-row-actions > a > svg { width: 14px; height: 14px; }

/* NPN-REMIT-LIST-STICKY-ACTIONS (2026-06-01): pin the Actions column to the
   right edge so it stays visible on wide tables that scroll horizontally.
   Operators reported the Actions column was "missing" on narrower windows —
   it was simply off-screen to the right (the table min-width is 1280px).
   Sticky only engages when the table overflows, so this is a no-op on
   tables that already fit. The left shadow signals the pinned edge. */
/* NPN-REMIT-FILTER-ONE-LINE (2026-06-05): status pills were truncating to
   "CHECKI"/"PENDIN" when the table squeezed columns — give Status a floor. */
.nv2-table th.nv2-col-status,
.nv2-table td.nv2-col-status { min-width: 108px; }

.nv2-table th.nv2-col-actions,
.nv2-table td.nv2-col-actions {
  position: sticky;
  right: 0;
  z-index: 2;
  background: white;
  box-shadow: -8px 0 8px -8px rgba(15, 23, 42, 0.18);
}
.nv2-table thead th.nv2-col-actions {
  z-index: 3;
  background: var(--nv2-panel-2);
}
.nv2-table tbody tr:hover td.nv2-col-actions { background: var(--nv2-panel-2); }
.nv2-table tbody tr.is-selected td.nv2-col-actions {
  background: color-mix(in srgb, var(--nv2-hub-accent, var(--nv2-brand)) 5%, white);
}

/* Section head */
.nv2-section-head {
  display: flex; align-items: center; justify-content: space-between;
  margin: 28px 0 12px;
}
.nv2-section-head h3 { font-size: 14px; font-weight: 700; }
.nv2-section-head p { font-size: 12px; color: var(--nv2-ink-3); margin-top: 2px; }

/* ═══════════════════════════════════════════════════════════════════════════
   FORMS — fieldsets, inputs, side panels, action bars
   ═══════════════════════════════════════════════════════════════════════════ */

.nv2-form-grid { display: grid; grid-template-columns: 2fr 1fr; gap: 18px; align-items: start; }
@media (max-width: 991px) {
  .nv2-form-grid { grid-template-columns: 1fr; }
}
.nv2-entity-panels-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: 12px;
  margin-bottom: 20px;
}
.nv2-entity-panels-grid .card { margin-bottom: 0 !important; }

/* Remitter / customer view — balanced cards, no stretched empty panels */
.remitter-view-page .card { margin-bottom: 0; }
.remitter-view-page .card-body { padding: 1rem 1.25rem; }
.remitter-view-page .form-control-view {
  min-height: 2.25rem;
  display: flex;
  align-items: center;
}
.nv2-form-card {
  background: white;
  border: 1px solid var(--nv2-line);
  border-radius: var(--nv2-radius);
  overflow: hidden;
}
.nv2-fieldset { padding: 18px 22px; border-bottom: 1px solid var(--nv2-line-2); }
.nv2-fieldset:last-child { border-bottom: 0; }
.nv2-fieldset-title {
  font-size: 11px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.10em;
  color: var(--nv2-ink-3);
  margin-bottom: 14px;
  display: flex; align-items: center; gap: 6px;
}
.nv2-fieldset-title svg { width: 12px; height: 12px; color: var(--nv2-hub-accent, var(--nv2-brand)); }

.nv2-field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin-bottom: 12px; }
.nv2-field-row.is-full { grid-template-columns: 1fr; }
.nv2-field-row.is-thirds { grid-template-columns: 1fr 1fr 1fr; }
.nv2-field { display: flex; flex-direction: column; gap: 5px; }
.nv2-field-label {
  font-size: 12px; font-weight: 600;
  color: var(--nv2-ink);
  display: flex; align-items: center; gap: 4px;
}
.nv2-field-label .nv2-req { color: var(--nv2-accent); font-weight: 700; }
.nv2-field-input, .nv2-field-select, .nv2-field-textarea {
  padding: 9px 12px;
  border-radius: 7px;
  border: 1px solid var(--nv2-line);
  background: white;
  font-family: inherit; font-size: 13px;
  color: var(--nv2-ink);
  transition: all 140ms ease;
  width: 100%;
  box-sizing: border-box;
}
.nv2-field-input:hover, .nv2-field-select:hover, .nv2-field-textarea:hover { border-color: var(--nv2-ink-3); }
.nv2-field-input:focus, .nv2-field-select:focus, .nv2-field-textarea:focus {
  outline: none;
  border-color: var(--nv2-hub-accent, var(--nv2-brand));
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--nv2-hub-accent, var(--nv2-brand)) 14%, transparent);
}
.nv2-field-wrapper { position: relative; }
.nv2-field-input.has-prefix { padding-left: 38px; }
.nv2-field-prefix {
  position: absolute; left: 10px; top: 50%; transform: translateY(-50%);
  font-size: 12px; font-weight: 700;
  color: var(--nv2-ink-3);
  pointer-events: none;
}
.nv2-field-suffix {
  position: absolute; right: 10px; top: 50%; transform: translateY(-50%);
  font-size: 11px; font-weight: 600;
  color: var(--nv2-ink-3);
  pointer-events: none;
}
.nv2-field-help { font-size: 11.5px; color: var(--nv2-ink-3); }
.nv2-field-error { font-size: 11.5px; color: var(--nv2-accent); display: flex; align-items: center; gap: 4px; }
.nv2-field-input.is-error { border-color: var(--nv2-accent); }

.nv2-form-footer {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 22px;
  background: var(--nv2-panel-2);
  border-top: 1px solid var(--nv2-line);
}
.nv2-form-footer-actions { display: flex; gap: 8px; }

/* Side panel (calculation, summary) */
.nv2-side-panel {
  background: white;
  border: 1px solid var(--nv2-line);
  border-radius: var(--nv2-radius);
  overflow: hidden;
  position: sticky; top: 0;
}
.nv2-side-panel-header {
  padding: 14px 18px;
  background: linear-gradient(135deg, color-mix(in srgb, var(--nv2-hub-accent, var(--nv2-brand)) 12%, white), white);
  border-bottom: 1px solid var(--nv2-line-2);
}
.nv2-side-panel-header h3 {
  font-size: 13px; font-weight: 700;
  color: var(--nv2-hub-accent, var(--nv2-brand));
  text-transform: uppercase; letter-spacing: 0.08em;
}
.nv2-side-panel-body { padding: 16px 18px; }
.nv2-calc-row {
  display: flex; justify-content: space-between; align-items: center;
  padding: 8px 0;
  font-size: 13px;
}
.nv2-calc-row.is-divider { border-top: 1px solid var(--nv2-line-2); margin-top: 8px; padding-top: 14px; }
.nv2-calc-label { color: var(--nv2-ink-2); }
.nv2-calc-value { font-weight: 700; color: var(--nv2-ink); font-family: var(--nv2-font-display); }
.nv2-calc-row.is-total { padding: 14px 0 4px; font-size: 16px; }
.nv2-calc-row.is-total .nv2-calc-label { font-weight: 700; color: var(--nv2-ink); }
.nv2-calc-row.is-total .nv2-calc-value { color: var(--nv2-hub-accent, var(--nv2-brand)); font-size: 19px; }

/* CSV Dropzone */
.nv2-csv-dropzone {
  border: 2px dashed var(--nv2-line);
  border-radius: var(--nv2-radius);
  padding: 40px 24px;
  text-align: center;
  background: var(--nv2-panel-2);
  cursor: pointer;
  transition: all 200ms ease;
}
.nv2-csv-dropzone:hover {
  border-color: var(--nv2-hub-accent, var(--nv2-brand));
  background: color-mix(in srgb, var(--nv2-hub-accent, var(--nv2-brand)) 5%, white);
}
.nv2-csv-dropzone-icon {
  width: 56px; height: 56px;
  border-radius: 14px;
  background: var(--nv2-brand-soft);
  color: var(--nv2-hub-accent, var(--nv2-brand));
  display: grid; place-items: center;
  margin: 0 auto 12px;
}
.nv2-csv-dropzone-icon svg { width: 26px; height: 26px; }
.nv2-csv-dropzone h3 { font-size: 15px; font-weight: 700; margin-bottom: 4px; color: var(--nv2-ink); }
.nv2-csv-dropzone p { font-size: 12.5px; color: var(--nv2-ink-2); }
.nv2-csv-dropzone-formats { font-size: 11px; color: var(--nv2-ink-3); margin-top: 8px; font-family: var(--nv2-font-mono); }

/* ═══════════════════════════════════════════════════════════════════════════
   CARDS — Person, Queue, Hit, Bank approval, Rule, Match score, Merge compare
   ═══════════════════════════════════════════════════════════════════════════ */

/* Person card grid (Remitters / Beneficiaries) */
.nv2-people-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }
.nv2-person-card {
  background: white;
  border: 1px solid var(--nv2-line);
  border-radius: var(--nv2-radius);
  padding: 16px;
  transition: all 200ms ease;
  cursor: pointer;
  text-decoration: none;
  color: inherit;
  display: block;
}
.nv2-person-card:hover {
  transform: translateY(-2px);
  box-shadow: var(--nv2-shadow-md);
  border-color: var(--nv2-hub-accent, var(--nv2-brand));
}
.nv2-person-head { display: flex; gap: 12px; align-items: center; margin-bottom: 12px; }
.nv2-person-name { font-size: 14px; font-weight: 700; color: var(--nv2-ink); }
.nv2-person-id { font-family: var(--nv2-font-mono); font-size: 11px; color: var(--nv2-ink-3); margin-top: 2px; }
.nv2-person-stats { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; font-size: 11.5px; }
.nv2-person-stat { display: flex; flex-direction: column; gap: 2px; }
.nv2-person-stat-label { color: var(--nv2-ink-3); font-weight: 600; text-transform: uppercase; font-size: 9.5px; letter-spacing: 0.06em; }
.nv2-person-stat-value { color: var(--nv2-ink); font-weight: 700; }
.nv2-person-actions {
  display: flex; gap: 6px; margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--nv2-line-2);
}

/* Queue card (KYC, Approval Queue, etc.) */
.nv2-queue-list { display: flex; flex-direction: column; gap: 10px; }
.nv2-queue-card {
  background: white;
  border: 1px solid var(--nv2-line);
  border-radius: var(--nv2-radius);
  padding: 14px 18px;
  display: flex; align-items: center; gap: 16px;
  transition: all 200ms ease;
  cursor: pointer;
}
.nv2-queue-card:hover { border-color: var(--nv2-hub-accent, var(--nv2-brand)); box-shadow: var(--nv2-shadow-md); transform: translateY(-1px); }
.nv2-queue-card.is-urgent { border-left: 3px solid var(--nv2-accent); }
.nv2-queue-card.is-high-risk { border-left: 3px solid var(--nv2-warn); }
.nv2-qcard-body { flex: 1; min-width: 0; }
.nv2-qcard-title { display: flex; align-items: center; gap: 8px; }
.nv2-qcard-name { font-size: 14px; font-weight: 700; color: var(--nv2-ink); }
.nv2-qcard-meta { font-size: 12px; color: var(--nv2-ink-3); margin-top: 2px; }
.nv2-qcard-tags { display: flex; gap: 6px; margin-top: 6px; }
.nv2-qcard-tag {
  font-size: 10.5px; font-weight: 600;
  padding: 1px 7px;
  border-radius: 4px;
  background: var(--nv2-bg);
  color: var(--nv2-ink-2);
}
.nv2-qcard-tag.is-warn { background: var(--nv2-warn-soft); color: #92400e; }
.nv2-qcard-tag.is-danger { background: var(--nv2-danger-soft); color: #991b1b; }
.nv2-qcard-tag.is-info { background: var(--nv2-brand-soft); color: var(--nv2-brand); }
.nv2-qcard-risk { text-align: right; font-family: var(--nv2-font-display); }
.nv2-qcard-risk-score { font-size: 22px; font-weight: 700; line-height: 1; }
.nv2-qcard-risk-score.is-low { color: var(--nv2-ok); }
.nv2-qcard-risk-score.is-medium { color: var(--nv2-warn); }
.nv2-qcard-risk-score.is-high { color: var(--nv2-accent); }
.nv2-qcard-risk-label {
  font-size: 10px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--nv2-ink-3);
  margin-top: 4px;
}
.nv2-qcard-actions { display: flex; gap: 6px; }

/* Hit card (Sanctions, Duplicates) */
.nv2-hit-card {
  background: white;
  border: 1px solid var(--nv2-line);
  border-radius: var(--nv2-radius);
  padding: 16px 18px;
  margin-bottom: 10px;
  display: flex; gap: 16px; align-items: center;
}
.nv2-hit-match { text-align: center; font-family: var(--nv2-font-display); flex-shrink: 0; }
.nv2-hit-match-pct { font-size: 28px; font-weight: 800; line-height: 1; }
.nv2-hit-match-pct.is-high { color: var(--nv2-danger); }
.nv2-hit-match-pct.is-medium { color: var(--nv2-warn); }
.nv2-hit-match-pct.is-low { color: var(--nv2-ink-3); }
.nv2-hit-match-label { font-size: 9.5px; font-weight: 700; text-transform: uppercase; color: var(--nv2-ink-3); margin-top: 4px; letter-spacing: 0.08em; }
.nv2-hit-body { flex: 1; min-width: 0; }
.nv2-hit-actions { display: flex; flex-direction: column; gap: 6px; }

/* Match score badge (duplicates) */
.nv2-match-score-badge {
  display: inline-flex; flex-direction: column; align-items: center;
  font-family: var(--nv2-font-display);
  background: white; border: 2px solid;
  padding: 6px 10px;
  border-radius: 12px;
  min-width: 70px;
}
.nv2-match-score-badge .nv2-num { font-size: 22px; font-weight: 800; line-height: 1; }
.nv2-match-score-badge .nv2-lbl { font-size: 8.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; margin-top: 3px; }
.nv2-match-score-badge.is-high { border-color: var(--nv2-danger); color: var(--nv2-danger); }
.nv2-match-score-badge.is-medium { border-color: var(--nv2-warn); color: #b45309; }
.nv2-match-score-badge.is-low { border-color: var(--nv2-ink-3); color: var(--nv2-ink-3); }

/* Bank approval card */
.nv2-bank-card {
  background: white;
  border: 1px solid var(--nv2-line);
  border-radius: var(--nv2-radius);
  padding: 16px 18px;
  margin-bottom: 10px;
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: 16px;
  align-items: center;
}
.nv2-bank-card.is-urgent { border-left: 3px solid var(--nv2-accent); }
.nv2-bank-icon {
  width: 44px; height: 44px;
  border-radius: 9px;
  background: linear-gradient(135deg, #0ea5e9 0%, #4361ee 100%);
  color: white;
  display: grid; place-items: center;
  flex-shrink: 0;
}
.nv2-bank-icon svg { width: 22px; height: 22px; }
.nv2-bank-name { font-size: 14px; font-weight: 700; }
.nv2-bank-details { font-family: var(--nv2-font-mono); font-size: 12px; color: var(--nv2-ink-2); margin-top: 2px; }
.nv2-bank-meta { display: flex; gap: 12px; margin-top: 8px; font-size: 11.5px; color: var(--nv2-ink-3); }
.nv2-bank-meta strong { color: var(--nv2-ink); font-weight: 700; }

/* Rule card (auto-dispatcher) */
.nv2-rule-card {
  display: grid;
  grid-template-columns: auto 1fr auto auto auto;
  gap: 12px; align-items: center;
  background: white;
  border: 1px solid var(--nv2-line);
  border-radius: var(--nv2-radius);
  padding: 12px 16px;
  margin-bottom: 8px;
}
.nv2-rule-card.is-disabled { opacity: 0.55; }
.nv2-rule-priority {
  font-family: var(--nv2-font-display);
  font-size: 18px; font-weight: 800;
  color: var(--nv2-hub-accent, var(--nv2-brand));
  width: 38px; text-align: center;
}
.nv2-rule-meta { font-size: 12px; color: var(--nv2-ink-3); margin-top: 3px; }
.nv2-rule-name { font-size: 13.5px; font-weight: 700; }
.nv2-rule-conditions { display: flex; gap: 4px; flex-wrap: wrap; margin-top: 4px; }
.nv2-rule-cond {
  font-size: 10.5px; font-weight: 600;
  background: var(--nv2-bg);
  padding: 2px 7px; border-radius: 4px;
  color: var(--nv2-ink-2);
}

/* Upload tile */
.nv2-upload-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; }
.nv2-upload-tile {
  background: white;
  border: 1px solid var(--nv2-line);
  border-radius: var(--nv2-radius);
  padding: 18px 18px 16px;
  cursor: pointer;
  transition: all 200ms ease;
  position: relative; overflow: hidden;
  text-align: left;
  font-family: inherit;
}
.nv2-upload-tile:hover {
  transform: translateY(-2px);
  box-shadow: var(--nv2-shadow-md);
  border-color: var(--nv2-hub-accent, var(--nv2-brand));
}
.nv2-upload-tile-icon {
  width: 38px; height: 38px;
  border-radius: 9px;
  display: grid; place-items: center;
  margin-bottom: 12px;
}
.nv2-upload-tile-icon svg { width: 18px; height: 18px; }
.nv2-upload-tile-name { font-size: 14px; font-weight: 700; color: var(--nv2-ink); margin-bottom: 4px; }
.nv2-upload-tile-desc { font-size: 12px; color: var(--nv2-ink-2); line-height: 1.4; min-height: 32px; }
.nv2-upload-tile-cta {
  margin-top: 14px;
  font-size: 11.5px; font-weight: 700;
  color: var(--nv2-hub-accent, var(--nv2-brand));
  display: flex; align-items: center; gap: 4px;
}

/* Merge compare layout */
.nv2-merge-compare {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  gap: 18px;
  align-items: stretch;
}
.nv2-merge-card {
  background: white;
  border: 2px solid var(--nv2-line);
  border-radius: var(--nv2-radius);
  padding: 20px;
}
.nv2-merge-card.is-primary { border-color: var(--nv2-ok); position: relative; }
.nv2-merge-card.is-primary::before {
  content: 'KEEP';
  position: absolute; top: 10px; right: 12px;
  font-size: 9.5px; font-weight: 800;
  background: var(--nv2-ok); color: white;
  padding: 2px 7px; border-radius: 999px;
  letter-spacing: 0.05em;
}
.nv2-merge-card.is-duplicate { border-color: var(--nv2-accent); position: relative; }
.nv2-merge-card.is-duplicate::before {
  content: 'MERGE INTO PRIMARY';
  position: absolute; top: 10px; right: 12px;
  font-size: 9.5px; font-weight: 800;
  background: var(--nv2-accent); color: white;
  padding: 2px 7px; border-radius: 999px;
  letter-spacing: 0.05em;
}
.nv2-merge-arrow {
  align-self: center;
  width: 50px; height: 50px;
  border-radius: 50%;
  background: var(--nv2-brand-soft);
  color: var(--nv2-brand);
  display: grid; place-items: center;
}
.nv2-merge-arrow svg { width: 22px; height: 22px; }
.nv2-merge-field {
  display: flex; justify-content: space-between; gap: 12px;
  padding: 6px 0; font-size: 12.5px;
  border-bottom: 1px solid var(--nv2-line-2);
}
.nv2-merge-field:last-child { border-bottom: 0; }
.nv2-merge-field-label { color: var(--nv2-ink-3); font-weight: 600; }
.nv2-merge-field-value { color: var(--nv2-ink); font-weight: 600; text-align: right; max-width: 60%; }
.nv2-merge-field.is-diff { background: #fef3c7; padding-left: 8px; padding-right: 8px; border-radius: 4px; }
.nv2-merge-field.is-diff .nv2-merge-field-value { color: #92400e; }

/* ═══════════════════════════════════════════════════════════════════════════
   ACTIVITY / TIMELINE / OVERLAYS
   ═══════════════════════════════════════════════════════════════════════════ */

/* Activity feed */
.nv2-activity-card {
  background: white;
  border: 1px solid var(--nv2-line);
  border-radius: var(--nv2-radius);
  overflow: hidden;
}
.nv2-activity-card-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 18px;
  border-bottom: 1px solid var(--nv2-line-2);
}
.nv2-activity-card-header h3 { font-size: 14px; font-weight: 700; }
.nv2-activity-card-header a { font-size: 12px; color: var(--nv2-brand); text-decoration: none; }
.nv2-activity-row {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 18px;
  border-bottom: 1px solid var(--nv2-line-2);
  font-size: 13px;
}
.nv2-activity-row:last-child { border-bottom: 0; }
.nv2-activity-icon {
  width: 32px; height: 32px;
  border-radius: 8px;
  display: grid; place-items: center;
  flex-shrink: 0;
}
.nv2-activity-icon svg { width: 14px; height: 14px; }
.nv2-activity-text { flex: 1; min-width: 0; color: var(--nv2-ink); }
.nv2-activity-time { font-size: 11px; color: var(--nv2-ink-3); white-space: nowrap; }

/* Timeline */
.nv2-timeline {
  background: white;
  border: 1px solid var(--nv2-line);
  border-radius: var(--nv2-radius);
  padding: 0;
}
.nv2-timeline-event {
  display: flex; gap: 14px;
  padding: 16px 22px;
  border-bottom: 1px solid var(--nv2-line-2);
  position: relative;
}
.nv2-timeline-event:last-child { border-bottom: 0; }
.nv2-timeline-event::before {
  content: '';
  position: absolute;
  left: 35px; top: 0; bottom: 0;
  width: 2px;
  background: var(--nv2-line);
}
.nv2-timeline-event:last-child::before { bottom: 50%; }
.nv2-timeline-event:first-child::before { top: 50%; }
.nv2-timeline-marker {
  width: 24px; height: 24px;
  border-radius: 50%;
  background: white;
  border: 2px solid var(--nv2-hub-accent, var(--nv2-brand));
  display: grid; place-items: center;
  flex-shrink: 0;
  z-index: 1;
  margin-top: 6px;
}
.nv2-timeline-marker svg { width: 11px; height: 11px; color: var(--nv2-hub-accent, var(--nv2-brand)); }
.nv2-timeline-marker.is-success { border-color: var(--nv2-ok); }
.nv2-timeline-marker.is-success svg { color: var(--nv2-ok); }
.nv2-timeline-marker.is-warn { border-color: var(--nv2-warn); }
.nv2-timeline-marker.is-warn svg { color: var(--nv2-warn); }
.nv2-timeline-marker.is-danger { border-color: var(--nv2-danger); }
.nv2-timeline-marker.is-danger svg { color: var(--nv2-danger); }
.nv2-timeline-body { flex: 1; min-width: 0; }
.nv2-timeline-line1 { font-size: 13.5px; color: var(--nv2-ink); }
.nv2-timeline-line1 strong { font-weight: 700; }
.nv2-timeline-line2 { font-size: 12px; color: var(--nv2-ink-2); margin-top: 4px; line-height: 1.5; }
.nv2-timeline-meta {
  display: flex; gap: 12px; align-items: center;
  margin-top: 6px;
  font-size: 11px; color: var(--nv2-ink-3);
}

/* Sticky action bar (forms) */
.nv2-action-bar {
  position: sticky; bottom: 0;
  background: white;
  border-top: 1px solid var(--nv2-line);
  padding: 14px 26px;
  display: flex; justify-content: space-between; align-items: center;
  margin: 22px -28px -64px;
  box-shadow: 0 -4px 12px rgba(15, 23, 42, 0.04);
  z-index: 5;
}

/* Dropdown menu (bell, avatar, showcase picker) */
.nv2-dropdown {
  position: absolute;
  top: calc(100% + 8px); right: 0;
  background: white;
  border-radius: 12px;
  box-shadow: var(--nv2-shadow-xl);
  border: 1px solid var(--nv2-line);
  min-width: 280px;
  opacity: 0;
  transform: translateY(-8px) scale(0.96);
  pointer-events: none;
  transition: opacity 180ms ease, transform 220ms cubic-bezier(0.16, 1, 0.3, 1);
  z-index: 200;
  overflow: hidden;
}
.nv2-dropdown.is-open { opacity: 1; transform: translateY(0) scale(1); pointer-events: auto; }

.nv2-menu-list { padding: 6px; }
.nv2-menu-list a, .nv2-menu-list button {
  display: flex; align-items: center; gap: 10px;
  width: 100%;
  padding: 8px 10px;
  border: 0; background: transparent;
  font-family: inherit; font-size: 13px;
  color: var(--nv2-ink);
  text-decoration: none;
  cursor: pointer;
  border-radius: 7px;
  text-align: left;
}
.nv2-menu-list a:hover, .nv2-menu-list button:hover { background: var(--nv2-panel-2); }
.nv2-menu-list svg { width: 14px; height: 14px; color: var(--nv2-ink-2); }
.nv2-menu-divider { height: 1px; background: var(--nv2-line-2); margin: 4px 6px; }
.nv2-menu-list .is-danger { color: var(--nv2-danger); }
.nv2-menu-kbd {
  margin-left: auto;
  font-family: inherit; font-size: 10.5px;
  background: var(--nv2-bg);
  border: 1px solid var(--nv2-line);
  padding: 1px 6px;
  border-radius: 4px;
  color: var(--nv2-ink-3);
}

/* Notifications panel */
.nv2-notif-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 16px;
  border-bottom: 1px solid var(--nv2-line-2);
}
.nv2-notif-list { max-height: 360px; overflow-y: auto; }
.nv2-notif-item {
  display: flex; gap: 12px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--nv2-line-2);
  cursor: pointer;
  transition: background 140ms ease;
}
.nv2-notif-item:hover { background: var(--nv2-panel-2); }
.nv2-notif-icon {
  width: 36px; height: 36px;
  border-radius: 9px;
  display: grid; place-items: center;
  flex-shrink: 0;
}
.nv2-notif-icon svg { width: 16px; height: 16px; }
.nv2-notif-body { flex: 1; min-width: 0; }
.nv2-notif-title { font-size: 13px; font-weight: 600; color: var(--nv2-ink); margin-bottom: 2px; }
.nv2-notif-desc { font-size: 12px; color: var(--nv2-ink-2); line-height: 1.4; }
.nv2-notif-time { font-size: 11px; color: var(--nv2-ink-3); margin-top: 4px; }
.nv2-notif-unread { width: 7px; height: 7px; background: var(--nv2-brand); border-radius: 50%; flex-shrink: 0; margin-top: 6px; }
/* The raw type of an alert the console's register does not know. Rendered ONCE
   per row and only for an unregistered type (overlays.jsx reads typePill, which
   operator-bell.server.js#mapRow leaves null for every registered one). */
.nv2-notif-pill {
  display: inline-flex; align-items: center; margin: 0 0 3px;
  padding: 1px 6px; border-radius: 999px;
  font-size: 10px; font-weight: 700; letter-spacing: .02em;
  color: var(--nv2-ink-3); background: var(--nv2-surface-2, #f1f5f9);
  border: 1px solid var(--nv2-line, #e5e7eb);
}

/* Search palette */
.nv2-palette-overlay {
  position: fixed; inset: 0;
  background: rgba(15, 23, 42, 0.45);
  backdrop-filter: blur(6px);
  display: none;
  align-items: flex-start; justify-content: center;
  padding-top: 12vh;
  z-index: 1000;
  animation: nv2-fade-in 180ms ease;
}
.nv2-palette-overlay.is-open { display: flex; }
.nv2-palette {
  width: 660px; max-height: 70vh;
  background: white;
  border-radius: 16px;
  box-shadow: var(--nv2-shadow-xl);
  display: flex; flex-direction: column;
  overflow: hidden;
  animation: nv2-slide-down 220ms cubic-bezier(0.16, 1, 0.3, 1);
}
@keyframes nv2-fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes nv2-slide-down { from { opacity: 0; transform: translateY(-12px); } to { opacity: 1; transform: translateY(0); } }
@keyframes nv2-hub-fade { from { opacity: 0; transform: translateX(8px); } to { opacity: 1; transform: translateX(0); } }
.nv2-hub-fade { animation: nv2-hub-fade 280ms cubic-bezier(0.16, 1, 0.3, 1); }

/* ─── Action Centre Overview (HTML mock parity) ───────────────────────── */
.ac-ov { display: flex; flex-direction: column; gap: 14px; }
.ac-ov-header { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: flex-start; gap: 12px; }
.ac-ov-title { margin: 0 0 4px; font-size: 1.45rem; font-weight: 800; color: var(--nv2-ink); letter-spacing: -0.02em; }
.ac-ov-subtitle { margin: 0; color: var(--nv2-ink-3); font-size: 0.86rem; max-width: 52rem; }
.ac-ov-header-actions { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.ac-ov-badge {
  display: inline-flex; align-items: center; gap: 6px;
  border: 1px solid var(--nv2-line, #e4e9f2); background: #fff; border-radius: 999px;
  padding: 6px 10px; font-size: 12px; color: var(--nv2-ink-2);
}
.ac-ov-dot { width: 9px; height: 9px; border-radius: 50%; display: inline-block; flex: 0 0 auto; }

.ac-ov-kpi-grid {
  display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 12px;
}
.ac-ov-kpi {
  text-align: left; border: 1px solid var(--nv2-line, #e4e9f2); border-radius: 13px;
  background: #fff; padding: 14px; box-shadow: 0 3px 12px rgba(26,42,74,.035);
  cursor: pointer; display: flex; flex-direction: column; gap: 10px;
  font: inherit; color: inherit; min-width: 0;
}
.ac-ov-kpi:hover { border-color: #c9d4ea; }
.ac-ov-kpi-top { display: flex; gap: 12px; align-items: center; min-width: 0; }
.ac-ov-kpi-copy { min-width: 0; flex: 1; }
.ac-ov-kpi-icon {
  width: 42px; height: 42px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  flex: 0 0 42px; line-height: 0;
}
.ac-ov-kpi-icon svg { display: block; flex: 0 0 auto; }
.ac-ov-kpi-icon.tone-blue, .ac-ov-kpi.tone-blue .ac-ov-kpi-icon { background: #dbeafe; color: #1d4ed8; }
.ac-ov-kpi-icon.tone-red, .ac-ov-kpi.tone-red .ac-ov-kpi-icon { background: #fee2e2; color: #dc2626; }
.ac-ov-kpi-icon.tone-amber, .ac-ov-kpi.tone-amber .ac-ov-kpi-icon { background: #fef3c7; color: #d97706; }
.ac-ov-kpi-icon.tone-green, .ac-ov-kpi.tone-green .ac-ov-kpi-icon { background: #d1fae5; color: #059669; }
.ac-ov-kpi-label { color: var(--nv2-ink-3); font-size: 0.74rem; font-weight: 700; }
.ac-ov-kpi-value { font-size: 1.55rem; line-height: 1.1; font-weight: 850; margin-top: 2px; }
.ac-ov-kpi-trend { font-size: 0.71rem; color: var(--nv2-ink-3); }
.ac-ov-kpi-trend.is-alert { color: #dc2626; font-weight: 700; }

.ac-ov-card {
  border: 1px solid var(--nv2-line, #e4e9f2); border-radius: 13px; background: #fff;
  box-shadow: 0 3px 12px rgba(26,42,74,.035); min-width: 0; overflow: hidden;
  display: flex; flex-direction: column;
}
.ac-ov-card-head {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 14px 14px 8px; flex: 0 0 auto;
}
.ac-ov-card-title { margin: 0; font-size: 0.92rem; font-weight: 800; min-width: 0; }
.ac-ov-card-body { padding: 4px 14px 14px; min-height: 180px; min-width: 0; }
.ac-ov-link {
  border: 0; background: none; color: var(--nv2-brand, #2f6fed); font-size: 0.72rem;
  font-weight: 700; text-decoration: none; cursor: pointer; padding: 0; font-family: inherit;
  flex: 0 0 auto; white-space: nowrap;
}
.ac-ov-link:hover { text-decoration: underline; }

.ac-ov-filters { padding: 14px; }
.ac-ov-filter-grid {
  display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 10px; align-items: end;
}
.ac-ov-filter-grid label { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.ac-ov-filter-grid label > span { font-size: 0.68rem; font-weight: 750; color: var(--nv2-ink-3); }
.ac-ov-filter-grid select {
  border: 1px solid var(--nv2-line, #e4e9f2); border-radius: 8px; min-height: 38px;
  font-size: 0.8rem; padding: 0 10px; background: #fff; color: var(--nv2-ink); font-family: inherit;
}
.ac-ov-filter-actions { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.ac-ov-text-btn {
  border: 0; background: none; color: var(--nv2-brand); font-size: 0.8rem; cursor: pointer;
  padding: 0; font-family: inherit;
}
.ac-ov-filter-chips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.ac-ov-chip {
  border: 1px solid var(--nv2-line, #e4e9f2); border-radius: 999px; background: #f8fafc;
  padding: 4px 10px; font-size: 0.72rem; color: var(--nv2-ink-2);
}

.ac-ov-layout {
  display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: 12px; align-items: start;
}
.ac-ov-main { display: flex; flex-direction: column; gap: 12px; min-width: 0; }
.ac-ov-rail { display: flex; flex-direction: column; gap: 12px; }
.ac-ov-chart-grid {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px;
}
.ac-ov-two { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.ac-ov-side-body { padding: 4px 14px 12px; }

.ac-ov-dough-wrap {
  display: flex; flex-direction: column; align-items: center; gap: 14px; min-height: 0;
}
.ac-ov-dough {
  border-radius: 50%; position: relative; flex: 0 0 auto;
  display: grid; place-items: center;
}
.ac-ov-dough-svg { display: block; }
.ac-ov-dough-arc {
  transition: opacity 0.15s, stroke-width 0.15s;
  cursor: pointer;
}
.ac-ov-dough-arc:hover { opacity: 0.78; }
.ac-ov-legend { list-style: none; margin: 0; padding: 0; width: 100%; min-width: 0; }
.ac-ov-legend li {
  display: grid; grid-template-columns: 10px minmax(0, 1fr) auto; align-items: center; gap: 8px;
  font-size: 0.72rem; padding: 4px 0; color: var(--nv2-ink-2);
  border-bottom: 1px solid #f1f4f9; cursor: default;
  transition: background 0.15s;
}
.ac-ov-legend li:hover { background: #f6f9ff; }
.ac-ov-legend li:last-child { border-bottom: 0; }
.ac-ov-legend-swatch { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; }
.ac-ov-legend-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ac-ov-legend strong { color: var(--nv2-ink); font-variant-numeric: tabular-nums; }

.ac-ov-hbars { display: flex; flex-direction: column; gap: 10px; padding-top: 4px; }
.ac-ov-hbar-row {
  display: grid; grid-template-columns: minmax(88px, 34%) 1fr 40px; gap: 8px; align-items: center;
  padding: 4px 6px; margin: -4px -6px; border-radius: 6px; cursor: default;
  transition: background 0.15s;
}
.ac-ov-hbar-row:hover { background: #f6f9ff; }
.ac-ov-hbar-label { font-size: 0.72rem; color: var(--nv2-ink-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ac-ov-hbar-track { height: 14px; background: #eef1f6; border-radius: 8px; overflow: hidden; min-width: 0; }
.ac-ov-hbar-fill { height: 100%; border-radius: 8px; transition: filter 0.15s; }
.ac-ov-hbar-row:hover .ac-ov-hbar-fill { filter: brightness(1.08); }
.ac-ov-hbar-val { font-size: 0.72rem; text-align: right; font-variant-numeric: tabular-nums; }

.ac-ov-vbars { display: flex; align-items: flex-end; gap: 10px; height: 180px; padding-top: 8px; }
.ac-ov-vbar-col {
  flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: center; gap: 6px;
  height: 100%; cursor: default; padding: 4px 2px; border-radius: 6px;
  transition: background 0.15s;
}
.ac-ov-vbar-col:hover { background: #f6f9ff; }
.ac-ov-vbar-track {
  flex: 1; width: 100%; max-width: 28px; background: #eef1f6; border-radius: 8px;
  display: flex; align-items: flex-end; overflow: visible; position: relative;
}
.ac-ov-vbar-fill { width: 100%; border-radius: 8px; min-height: 4px; transition: filter 0.15s; position: relative; }
.ac-ov-vbar-col:hover .ac-ov-vbar-fill { filter: brightness(1.08); }
.ac-ov-vbar-val-tip {
  position: absolute; top: -18px; left: 50%; transform: translateX(-50%);
  font-size: 0.68rem; font-weight: 700; color: var(--nv2-ink); white-space: nowrap;
  opacity: 0; transition: opacity 0.15s; pointer-events: none;
}
.ac-ov-vbar-col:hover .ac-ov-vbar-val-tip { opacity: 1; }
.ac-ov-vbar-label { font-size: 0.65rem; color: var(--nv2-ink-3); text-align: center; line-height: 1.2; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.ac-ov-trend-wrap { display: flex; flex-direction: column; gap: 6px; height: 200px; }
.ac-ov-trend { width: 100%; height: 100%; overflow: visible; }
.ac-ov-trend-axis { display: flex; justify-content: space-between; font-size: 0.65rem; color: var(--nv2-ink-3); }
.ac-ov-trend-pt { cursor: pointer; }
.ac-ov-trend-dot { transition: stroke-width 0.15s, r 0.15s; stroke: transparent; }
.ac-ov-trend-pt:hover .ac-ov-trend-dot { stroke: rgba(47, 111, 237, 0.28); stroke-width: 6; }
.ac-ov-trend-hit { pointer-events: all; }

.ac-ov-module-grid {
  display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 10px; padding: 4px 14px 14px;
}
.ac-ov-module-stat {
  border: 1px solid var(--nv2-line, #e4e9f2); border-radius: 11px; background: #fff; padding: 12px;
  text-align: left; font: inherit; color: inherit; cursor: pointer; min-height: 92px;
}
.ac-ov-module-stat:hover { border-color: #c9d4ea; }
.ac-ov-module-label { color: var(--nv2-ink-3); font-size: 0.7rem; font-weight: 700; }
.ac-ov-module-value { font-weight: 850; font-size: 1.22rem; margin-top: 4px; }
.ac-ov-module-pct { font-size: 0.72rem; color: var(--nv2-ink-3); margin-top: 2px; }

.ac-ov-metric-row {
  display: flex; justify-content: space-between; align-items: center; gap: 10px;
  padding: 10px 0; border-bottom: 1px solid #edf0f5; font-size: 0.78rem;
}
.ac-ov-metric-row:last-child { border-bottom: 0; }
.ac-ov-metric-row.is-btn {
  width: 100%; border-left: 0; border-right: 0; border-top: 0; background: none;
  cursor: pointer; font: inherit; color: inherit; text-align: left;
}
.ac-ov-metric-name { display: flex; gap: 8px; align-items: center; min-width: 0; }
.ac-ov-metric-row .is-ok { color: #059669; }
.ac-ov-metric-row .is-bad { color: #dc2626; }
/* DASH-55: a rate with an empty denominator is neither good nor bad — it is
   absent. Renders the "—" placeholder neutral instead of borrowing is-ok green. */
.ac-ov-metric-row .ac-ov-muted { color: var(--nv2-ink-3); }
.ac-ov-health {
  border-radius: 999px; padding: 2px 8px; font-size: 0.68rem; font-weight: 700;
}
.ac-ov-health.is-ok { background: #d1fae5; color: #047857; }
.ac-ov-health.is-bad { background: #fee2e2; color: #b91c1c; }
/* DASH-46: DEGRADED is a real third state (a late/flapping heartbeat), and
   Unknown means "no signal exists" — neither is the same thing as FAILED, so
   neither borrows FAILED's red. */
.ac-ov-health.is-warn { background: #fef3c7; color: #b45309; }
.ac-ov-health.is-unknown { background: #f1f5f9; color: #475569; }

.ac-ov-insights {
  border: 1px solid #dce7ff; background: linear-gradient(90deg, #f3f7ff, #fbfdff);
  border-radius: 12px; padding: 12px 14px; display: flex; gap: 18px; flex-wrap: wrap;
  align-items: center; font-size: 0.76rem;
}
.ac-ov-insights-label { display: inline-flex; align-items: center; gap: 6px; color: var(--nv2-brand, #2f6fed); }
.ac-ov-insight-item { color: var(--nv2-ink-2); }
.ac-ov-footer {
  display: flex; flex-wrap: wrap; justify-content: space-between; gap: 8px;
  color: var(--nv2-ink-3); font-size: 0.7rem;
}
.ac-ov-empty { color: var(--nv2-ink-3); font-size: 0.78rem; padding: 12px 0; }
.ac-ov-empty-pad { padding: 28px 8px; text-align: center; line-height: 1.45; }

.ac-ov-mode-tabs {
  display: flex; gap: 6px; flex-wrap: wrap; margin: 0 0 12px;
}
.ac-ov-mode-tab {
  border: 1px solid var(--nv2-line, #e4e9f2); background: #fff; border-radius: 999px;
  padding: 7px 14px; font-size: 13px; font-weight: 650; color: var(--nv2-ink-2);
  cursor: pointer; font-family: inherit;
}
.ac-ov-mode-tab.is-active {
  background: var(--nv2-ink, #172033); color: #fff; border-color: var(--nv2-ink, #172033);
}

@media (max-width: 1199px) {
  .ac-ov-kpi-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .ac-ov-layout { grid-template-columns: 1fr; }
  .ac-ov-module-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .ac-ov-filter-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 900px) {
  .ac-ov-chart-grid, .ac-ov-two { grid-template-columns: 1fr; }
  .ac-ov-hbar-row { grid-template-columns: 90px 1fr 32px; }
}
@media (max-width: 640px) {
  .ac-ov-kpi-grid, .ac-ov-module-grid, .ac-ov-filter-grid { grid-template-columns: 1fr 1fr; }
  .ac-ov-title { font-size: 1.25rem; }
}
@media (max-width: 420px) {
  .ac-ov-kpi-grid, .ac-ov-module-grid { grid-template-columns: 1fr; }
}

/* -- Remittance 360 Dashboard (/remittance/dashboard) ----------------- */
.rem-d { display: flex; flex-direction: column; gap: 14px; }
.rem-d-toolbar { display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; flex-wrap: wrap; }
.rem-d-crumb { display: flex; align-items: center; gap: 6px; font-size: 0.78rem; color: var(--nv2-ink-3); margin-bottom: 6px; }
.rem-d-crumb span { opacity: 0.55; }
.rem-d-title { margin: 0; font-size: 1.5rem; font-weight: 800; color: var(--nv2-ink); letter-spacing: -0.02em; }
.rem-d-subtitle { margin: 4px 0 0; color: var(--nv2-ink-3); font-size: 0.85rem; }
.rem-d-toolbar-actions { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.rem-d-period {
  display: inline-flex; align-items: center; min-height: 32px; padding: 0 10px;
  border: 1px solid var(--nv2-line-2, #e4e9f2); border-radius: 8px;
  background: #fff; font-size: 0.78rem; color: var(--nv2-ink-2); font-weight: 600;
}
.rem-d-kpi-grid { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 12px; }
.rem-d-kpi {
  background: #fff; border: 1px solid var(--nv2-line-2, #e4e9f2); border-radius: 14px;
  box-shadow: 0 3px 12px rgba(26, 42, 74, 0.035); padding: 14px;
}
.rem-d-kpi-row { display: flex; gap: 12px; align-items: flex-start; }
.rem-d-kpi-icon {
  width: 42px; height: 42px; border-radius: 50%; display: grid; place-items: center; flex: 0 0 auto;
}
.rem-d-kpi-icon--primary { background: #e8effd; color: #2f6fed; }
.rem-d-kpi-icon--success { background: #e6f7ef; color: #14a66f; }
.rem-d-kpi-icon--warning { background: #fff4e5; color: #c2410c; }
.rem-d-kpi-icon--danger { background: #fdebec; color: #e5484d; }
.rem-d-kpi-icon--info { background: #e6f6fa; color: #25a4bf; }
.rem-d-kpi-label { color: var(--nv2-ink-3); font-size: 0.72rem; font-weight: 750; }
.rem-d-kpi-value { font-size: 1.45rem; line-height: 1.15; font-weight: 850; margin-top: 2px; color: var(--nv2-ink); }
.rem-d-kpi-foot { margin-top: 8px; font-size: 0.7rem; color: var(--nv2-ink-3); }
.rem-d-kpi-foot.is-up { color: #14a66f; }
.rem-d-kpi-foot.is-down { color: #e5484d; }
.rem-d-layout { display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: 12px; align-items: start; }
.rem-d-main { display: flex; flex-direction: column; gap: 12px; min-width: 0; }
.rem-d-chart-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
.rem-d-rail { display: flex; flex-direction: column; gap: 12px; min-width: 0; }
.rem-d-card {
  background: #fff; border: 1px solid var(--nv2-line-2, #e4e9f2); border-radius: 14px;
  box-shadow: 0 3px 12px rgba(26, 42, 74, 0.035); overflow: hidden;
}
.rem-d-card-head {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 14px 14px 4px;
}
.rem-d-card-title { margin: 0; font-size: 0.9rem; font-weight: 800; color: var(--nv2-ink); }
.rem-d-report-link { font-size: 0.72rem; font-weight: 700; color: #2f6fed; text-decoration: none; }
.rem-d-report-link:hover { text-decoration: underline; }
.rem-d-card-body { padding: 10px 14px 14px; }
.rem-d-recent-card .rem-d-card-body { padding: 0; }
.rem-d-chart { min-height: 180px; }
.rem-d-chart-short { min-height: 160px; }
.rem-d-lifecycle-card { grid-column: 1 / -1; }
.rem-d-lifecycle-list { list-style: none; margin: 0; padding: 0; min-width: 0; }
.rem-d-lifecycle-list li {
  display: grid;
  grid-template-columns: minmax(96px, 1.2fr) minmax(48px, 1fr) auto;
  gap: 10px;
  align-items: center;
  padding: 6px 0;
  font-size: 0.74rem;
  min-height: 28px;
  border-bottom: 1px solid #f0f2f6;
}
.rem-d-lifecycle-list li:last-child { border-bottom: 0; }
.rem-d-lifecycle-label { display: flex; align-items: center; gap: 6px; color: var(--nv2-ink-2); min-width: 0; }
.rem-d-lifecycle-name {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.rem-d-lifecycle-track {
  height: 10px; background: #eef1f6; border-radius: 8px; overflow: hidden; min-width: 0;
}
.rem-d-lifecycle-fill { height: 100%; border-radius: 8px; min-width: 0; }
.rem-d-lifecycle-val {
  font-variant-numeric: tabular-nums; text-align: right; min-width: 1.5rem;
}
.rem-d-dot { width: 9px; height: 9px; border-radius: 50%; display: inline-block; flex: 0 0 auto; }
.rem-d-dot--danger { background: #e5484d; }
.rem-d-dot--warning { background: #f28c28; }
.rem-d-dot--info { background: #2f6fed; }
.rem-d-metric-row {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 8px 0; border-bottom: 1px solid #edf0f5; font-size: 0.78rem;
}
.rem-d-metric-row:last-child { border-bottom: 0; }
/* Clickable alert rows: keep the row layout, drop anchor underline/colour, and
   hint interactivity on hover. */
.rem-d-metric-row--link { text-decoration: none; color: inherit; cursor: pointer; transition: background .12s ease; }
.rem-d-metric-row--link:hover { background: #f6f8fc; }
.rem-d-metric-name { display: flex; align-items: center; gap: 8px; min-width: 0; }
.rem-d-failures { display: flex; flex-direction: column; }
.rem-d-failure-row {
  display: grid; grid-template-columns: 1fr auto; gap: 8px; align-items: center;
  padding: 7px 0; border-bottom: 1px solid #edf0f5; font-size: 0.77rem;
}
.rem-d-failure-row:last-child { border-bottom: 0; }
.rem-d-failure-row span { display: inline-flex; align-items: center; gap: 8px; }
.rem-d-failure-total { color: #e5484d; font-weight: 800; }
.rem-d-table-wrap { overflow-x: auto; }
.rem-d-table { width: 100%; border-collapse: collapse; font-size: 0.76rem; }
.rem-d-table th, .rem-d-table td {
  padding: 10px 12px; border-bottom: 1px solid #edf0f5; vertical-align: middle; text-align: left; white-space: nowrap;
}
.rem-d-table thead th {
  color: var(--nv2-ink-3); font-size: 0.66rem; letter-spacing: 0.02em; font-weight: 800; text-transform: uppercase;
}
.rem-d-table a { color: #2f6fed; font-weight: 700; text-decoration: none; }
.rem-d-table a:hover { text-decoration: underline; }
.rem-d-pill {
  display: inline-flex; align-items: center; padding: 3px 8px; border-radius: 999px;
  font-size: 0.68rem; font-weight: 750; white-space: nowrap;
}
.rem-d-pill--success { background: #e6f7ef; color: #0f7a52; }
.rem-d-pill--danger { background: #fdebec; color: #b42318; }
.rem-d-pill--warning { background: #fff4e5; color: #c2410c; }
.rem-d-pill--info { background: #e6f6fa; color: #0e7490; }
.rem-d-pill--primary { background: #e8effd; color: #1d4ed8; }
.rem-d-eye {
  border: 0; background: #f3f5f9; border-radius: 8px; width: 28px; height: 28px;
  display: inline-grid; place-items: center; cursor: pointer; color: var(--nv2-ink-2);
}
.rem-d-eye:hover { background: #e8effd; color: #2f6fed; }
.rem-d-health {
  display: inline-flex; align-items: center; padding: 2px 8px; border-radius: 999px;
  font-size: 0.68rem; font-weight: 750;
}
.rem-d-health.is-ok { background: #e6f7ef; color: #0f7a52; }
.rem-d-health.is-bad { background: #fdebec; color: #b42318; }
/* DASH-46: see .ac-ov-health.is-warn — DEGRADED and Unknown are distinct states
   and must not both be painted as FAILED. */
.rem-d-health.is-warn { background: #fef3c7; color: #b45309; }
.rem-d-health.is-unknown { background: #f1f5f9; color: #475569; }
.rem-d-insights {
  border: 1px solid #dce7ff; background: linear-gradient(90deg, #f3f7ff, #fbfdff);
  border-radius: 12px; padding: 10px 14px; display: flex; gap: 18px; flex-wrap: wrap;
  align-items: center; font-size: 0.75rem; color: var(--nv2-ink-2);
}
.rem-d-insights-label { display: inline-flex; align-items: center; gap: 6px; color: #2f6fed; }
.rem-d-foot {
  display: flex; flex-wrap: wrap; justify-content: space-between; gap: 8px;
  color: var(--nv2-ink-3); font-size: 0.72rem;
}
.rem-d-trend-labels {
  display: flex; justify-content: space-between; gap: 4px; margin-top: 4px;
  font-size: 0.65rem; color: var(--nv2-ink-3);
}
.rem-d-empty { color: var(--nv2-ink-3); font-size: 0.78rem; padding: 8px 0; }
/* DASH-50(b): caption under the Open Failures total explaining why it counts a
   different population from the Failed KPI on the same screen. */
.rem-d-failure-note {
  margin: 8px 0 0; padding-top: 8px; border-top: 1px solid #eef1f6;
  color: var(--nv2-ink-3); font-size: 0.68rem; line-height: 1.45;
}
@media (max-width: 1399px) {
  .rem-d-kpi-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 1199px) {
  .rem-d-layout { grid-template-columns: 1fr; }
  .rem-d-chart-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 760px) {
  .rem-d-kpi-grid, .rem-d-chart-grid { grid-template-columns: 1fr; }
  .rem-d-lifecycle-list li {
    grid-template-columns: minmax(0, 1fr) auto;
  }
  .rem-d-lifecycle-track { display: none; }
  .rem-d-title { font-size: 1.25rem; }
}

/* HUBFIX-1 (2026-09-04) — `li.nv2-leaf-pinnable` below is `display: flex`,
   which is right for a CLASSIC leaf (one <a> + one star) and WRONG for a
   task-first ENTRY, whose <li> held three BLOCK children (.nv2-entry-row,
   .nv2-entry-hint and, before HUBFIX-3, .nv2-entry-views — HUBFIX-4 has since
   taken the hint too, leaving the row alone). They became
   side-by-side flex items competing for a 251px column, so the name was
   squeezed and wrapped or cut. Measured on staging deploy #29 at 1440:
   "Action Centre" 75px wide / scrollWidth 78 / 2 lines, "Integration Health
   (KYC pipeline)" 114px / 4 lines, "Reconciliation Breaks" 120px with
   scrollWidth 122 — the owner's "the text is blocked partly". The hover and
   active highlight were content-width too, which is the "turns half grey".
   An entry keeps the normal block flow; its own row is already a flex row. */
/* ── W5.4 · per-leaf pin star ─────────────────────────────────────────────
   The li becomes a flex row only when a star can render (nv2-leaf-pinnable),
   so unpinnable leaves keep their exact pre-W5.4 layout. The star is
   keyboard-reachable (a real button) and invisible until hover/focus so the
   list stays quiet; a pinned star stays visible. */
.nv2-hub-panel li.nv2-leaf-pinnable:not(.nv2-entry) { display: flex; align-items: center; }
.nv2-hub-panel li.nv2-leaf-pinnable > a,
.nv2-hub-panel li.nv2-leaf-pinnable > span { flex: 1 1 auto; min-width: 0; }
.nv2-pin-star {
  flex: 0 0 auto;
  border: 0; background: none; cursor: pointer;
  font-size: 12px; line-height: 1; padding: 2px 6px;
  color: var(--nv2-text-dim, #94a3b8);
  opacity: 0; transition: opacity 120ms ease, color 120ms ease;
}
.nv2-hub-panel li.nv2-leaf-pinnable:hover .nv2-pin-star,
.nv2-pin-star:focus-visible { opacity: 1; }
.nv2-pin-star.is-pinned { opacity: 1; color: var(--nv2-hub-accent, #f59e0b); }
.nv2-pin-star:hover { color: var(--nv2-hub-accent, #f59e0b); }

/* ═══════════════════════════════════════════════════════════════════════════
   RESPONSIVE SHELL — SHELL-RESP-1 (2026-09-03)
   ═══════════════════════════════════════════════════════════════════════════
   THE DEFECT. `.nv2-app` (line ~98 of this file) hard-codes
   `grid-template-columns: 72px 296px 1fr` with no breakpoint, so the third
   column — every page's content — started at x = 368px on EVERY viewport.
   At a 390px phone viewport that leaves 22px of content: the page begins
   off-screen. Measured independently by four builders on /dashboard/*,
   /agents and /treasury/routing (shots-routing-explain/routing-390-viewport.png).
   Nothing below the shell could fix it — the columns are reserved here.

   THE SHAPE OF THE FIX. Three bands, and only the two narrow ones carry any
   rule at all, so ≥1200px is byte-for-byte the layout that shipped:

     ≥1200px   unchanged. `.nv2-shell-nav` is `display: contents`, so the rail
               and the hub column stay DIRECT grid items of `.nv2-app` and the
               72/296/1fr grid resolves exactly as before; the drawer chrome
               (backdrop, hamburger, close button) is `display: none`.
     901–1199  the rail keeps its column; the hub column stops reserving 296px
               and becomes an off-canvas drawer that slides out from behind the
               rail, under the topbar. Content gains 296px.
     ≤900      neither the rail nor the hub column reserves a column. Content
               is the whole width (left edge = 0). Both panes travel together
               inside one off-canvas drawer — the rail as an icon+label column,
               the hub panel beside it — so every rail item (8 hubs, Help,
               Account Settings, Logout) stays reachable, which a bottom bar
               with eleven targets on a 390px screen would not.

   The drawer is opened by `.nv2-nav-toggle` in the topbar (shell.jsx), which
   carries aria-expanded/aria-controls; it closes on Escape, on a backdrop
   click, on the in-drawer close button and on any navigation. Focus is trapped
   inside it while open and returns to the toggle on close (shell.jsx).
   `visibility: hidden` on the closed drawer is load-bearing, not cosmetic: it
   is what keeps the off-canvas links out of the tab order and out of the
   accessibility tree without any JS that could disagree with the media query.

   No route, nav row, RBAC key or testid changes anywhere in this block.
   ═══════════════════════════════════════════════════════════════════════ */

/* Base — the three new elements are inert above 1199px. `display: contents`
   removes .nv2-shell-nav from the box tree entirely, which is what makes the
   ≥1200 grid identical to the pre-change one. */
.nv2-shell-nav      { display: contents; }
.nv2-shell-backdrop { display: none; }
.nv2-nav-toggle     { display: none; }
.nv2-nav-close      { display: none; }

/* ── Both narrow bands: the toggle and the backdrop come alive ─────────── */
@media (max-width: 1199px) {
  .nv2-nav-toggle {
    display: grid; place-items: center;
    width: 36px; height: 36px; flex: 0 0 36px;
    border: 0; border-radius: 9px;
    background: transparent; color: var(--nv2-ink-2);
    cursor: pointer;
    transition: background 140ms ease, color 140ms ease;
  }
  .nv2-nav-toggle:hover { background: var(--nv2-bg); color: var(--nv2-brand); }
  .nv2-nav-toggle:focus-visible { outline: 2px solid var(--nv2-brand); outline-offset: 2px; }

  .nv2-shell-backdrop {
    display: block;
    position: fixed; top: 0; right: 0; bottom: 0; left: 0;
    background: rgba(15, 23, 42, 0.42);
    opacity: 0; pointer-events: none;
    transition: opacity 200ms ease;
    z-index: 90;
  }
  .nv2-app.is-nav-open .nv2-shell-backdrop { opacity: 1; pointer-events: auto; }
}

/* ── 901–1199px: rail stays put, the hub column becomes the drawer ─────── */
@media (min-width: 901px) and (max-width: 1199px) {
  .nv2-app                { grid-template-columns: 72px 1fr; }
  .nv2-app.is-rail-pinned { grid-template-columns: 240px 1fr; }
  /* AVMENU-2 — the hub column is already a drawer in this band, so a personal
     page reserves nothing extra; re-declared because the base collapse pair is a
     two-class selector and would otherwise out-specify the two rules above. */
  .nv2-app.is-no-hub-panel                { grid-template-columns: 72px 1fr; }
  .nv2-app.is-rail-pinned.is-no-hub-panel { grid-template-columns: 240px 1fr; }
  .nv2-main-col           { grid-column: 2; min-width: 0; }

  /* Above the backdrop (90) and the panel (95) so the hamburger stays live
     while the drawer is open — clicking it again is the close gesture here.
     Still below the rail (100), which keeps the hover-expanded rail on top
     of the topbar exactly as it is at full width. */
  .nv2-topbar { z-index: 96; }

  .nv2-hub-panel-col {
    grid-column: 1;
    position: fixed; top: 60px; bottom: 0; left: 72px;
    width: 296px;
    z-index: 95;
    visibility: hidden;
    transform: translateX(calc(-100% - 72px));
    transition: transform 240ms cubic-bezier(0.16, 1, 0.3, 1), visibility 0s linear 240ms;
  }
  .nv2-app.is-rail-pinned .nv2-hub-panel-col {
    left: 240px;
    transform: translateX(calc(-100% - 240px));
  }
  .nv2-app.is-nav-open .nv2-hub-panel-col,
  .nv2-app.is-rail-pinned.is-nav-open .nv2-hub-panel-col {
    transform: none;
    visibility: visible;
    box-shadow: var(--nv2-shadow-lg);
    transition: transform 240ms cubic-bezier(0.16, 1, 0.3, 1), visibility 0s;
  }
  .nv2-hub-panel-col.nv2-pane { height: auto; }
}

/* ── ≤900px: one column of content, rail + hub panel in one drawer ─────── */
@media (max-width: 900px) {
  .nv2-app,
  .nv2-app.is-rail-pinned { grid-template-columns: 1fr; height: 100dvh; }
  /* AVMENU-2 — same reason as the 901-1199 band: one column, personal page or not. */
  .nv2-app.is-no-hub-panel,
  .nv2-app.is-rail-pinned.is-no-hub-panel { grid-template-columns: 1fr; }
  .nv2-pane               { height: 100%; }
  .nv2-main-col           { grid-column: 1; min-width: 0; }

  .nv2-shell-nav {
    display: flex;
    position: fixed; top: 0; left: 0; bottom: 0;
    width: min(100vw - 40px, 350px);
    background: var(--nv2-panel);
    z-index: 120;
    visibility: hidden;
    transform: translateX(-100%);
    transition: transform 260ms cubic-bezier(0.16, 1, 0.3, 1), visibility 0s linear 260ms;
  }
  .nv2-app.is-nav-open .nv2-shell-nav {
    transform: none;
    visibility: visible;
    box-shadow: 24px 0 60px -20px rgba(15, 23, 42, 0.5);
    transition: transform 260ms cubic-bezier(0.16, 1, 0.3, 1), visibility 0s;
  }
  .nv2-shell-backdrop { z-index: 110; }

  .nv2-nav-close {
    display: grid; place-items: center;
    position: absolute; top: 10px; right: 10px;
    width: 30px; height: 30px;
    border: 1px solid var(--nv2-line);
    border-radius: 8px;
    background: var(--nv2-panel);
    color: var(--nv2-ink-2);
    cursor: pointer;
    z-index: 5;
  }
  .nv2-nav-close:hover { background: var(--nv2-bg); color: var(--nv2-ink); }

  /* Rail — in-flow inside the drawer, icons with their labels under them.
     `position: relative` (not fixed) is deliberate: a fixed child of a
     transformed drawer resolves against the drawer, which works but reads as
     an accident. In flow it cannot drift. */
  .nv2-shell-nav .nv2-rail {
    position: relative; top: auto; left: auto; bottom: auto;
    flex: 0 0 80px;
    width: 80px !important;
    box-shadow: none !important;
    overflow-y: auto; overflow-x: hidden;
    padding: 12px 6px;
    z-index: auto;
  }
  /* Beat the hover/pin/collapse width rules, which are all specificity (0,2,0)
     and one of which is !important. */
  .nv2-shell-nav .nv2-rail:hover,
  .nv2-shell-nav .nv2-rail.is-hover,
  .nv2-shell-nav .nv2-rail.is-pinned,
  .nv2-shell-nav .nv2-rail.is-collapsed-after-click {
    width: 80px !important;
    box-shadow: none !important;
  }
  .nv2-shell-nav .nv2-rail > * { flex-shrink: 0; }
  /* The pin control sizes a grid column that does not exist at this width. */
  .nv2-shell-nav .nv2-rail-pin { display: none; }
  .nv2-shell-nav .nv2-brand-row { justify-content: center; margin-bottom: 6px; }
  .nv2-shell-nav .nv2-brand-text-wrap { display: none; }
  .nv2-shell-nav .nv2-rail .nv2-rail-section {
    opacity: 1 !important;
    text-align: center;
    padding: 8px 2px 2px;
    letter-spacing: 0.06em;
  }
  .nv2-shell-nav .nv2-hub-btn {
    flex-direction: column; gap: 3px;
    height: auto; min-height: 54px;
    padding: 7px 2px;
    text-align: center;
  }
  /* Hover tooltips are unreachable on touch — the label under the icon is
     the label now, so the floating one would only ever be a stray box. */
  .nv2-shell-nav .nv2-hub-btn[data-tooltip]::after { display: none; }
  .nv2-shell-nav .nv2-rail .nv2-hub-label {
    opacity: 1 !important;
    transform: none !important;
    font-size: 9.5px; font-weight: 600; line-height: 1.15;
    white-space: normal; overflow-wrap: anywhere;
  }
  .nv2-shell-nav .nv2-rail:hover .nv2-hub-badge,
  .nv2-shell-nav .nv2-rail.is-hover .nv2-hub-badge,
  .nv2-shell-nav .nv2-rail.is-pinned .nv2-hub-badge {
    position: absolute; top: 2px; right: 6px;
    margin-left: 0;
    font-size: 9px; padding: 1px 5px;
  }
  .nv2-shell-nav .nv2-hub-btn.is-active::before { left: -6px; top: 6px; bottom: 6px; }

  /* Hub panel — the rest of the drawer. */
  .nv2-shell-nav .nv2-hub-panel-col {
    grid-column: auto;
    position: relative;
    flex: 1 1 auto; min-width: 0; width: auto;
    border-right: 0;
  }

  /* Topbar — nothing removed but the breadcrumb path, which the drawer and
     the page's own H1 both carry. The environment chip stays: on a staging
     box that pill is a safety signal, not decoration. */
  .nv2-topbar { padding: 0 10px; gap: 6px; }
  .nv2-nav-toggle { width: 32px; height: 32px; flex: 0 0 32px; }
  .nv2-breadcrumb { min-width: 0; flex: 0 1 auto; overflow: hidden; }
  .nv2-breadcrumb > a,
  .nv2-breadcrumb > span:not(.nv2-env-chip) { display: none; }
  .nv2-env-chip { margin-left: 0; }
  .nv2-topbar-search { flex: 1 1 120px; min-width: 0; max-width: none; margin-left: auto; }
  .nv2-topbar-icon, .nv2-avatar-btn { width: 32px; height: 32px; flex: 0 0 32px; }

  /* PRE-EXISTING, exposed by the fix: the bell and account panels are anchored
     `right: 0` on their own trigger and carry a fixed inline width (360px and
     240px). Off a trigger whose right edge is ~328px on a 390px screen that put
     the notifications panel at x = -32, and `.nv2-main`'s `overflow: hidden`
     then clipped it. Nobody could see it before because the whole topbar was
     22px wide. Neutralising `position: relative` on the trigger re-anchors both
     panels to the topbar itself, so they drop full-width beneath it. */
  /* `!important` because the trigger's `position: relative` is an INLINE style
     in shell.jsx (`<div style={{ position: 'relative' }} data-topbar-trigger>`)
     and nothing else can outrank it. Without it the two rules below resolve
     against the 32px button and the panel renders 32px wide — verified. */
  .nv2-topbar [data-topbar-trigger] { position: static !important; }
  .nv2-topbar .nv2-dropdown {
    left: 0; right: 0;
    width: auto !important;
    min-width: 0;
    max-width: none;
  }

  /* PRE-EXISTING, same class: `.nv2-palette` is a hard 660px, so ⌘K's palette
     and the shortcuts modal both overflowed a 390px viewport by 270px. */
  .nv2-palette-overlay { padding-top: 8vh; padding-left: 12px; padding-right: 12px; }
  .nv2-palette { width: 100%; max-height: 78vh; }

  .nv2-content { padding: 18px 16px 56px; }
}

/* ── ≤640px: the type-ahead needs a full row to be usable ──────────────── */
@media (max-width: 640px) {
  .nv2-topbar {
    flex-wrap: wrap;
    height: auto; min-height: 56px;
    padding: 8px 10px;
    row-gap: 8px;
  }
  /* `order` moves it to the second row without touching the DOM order, so the
     tab order stays breadcrumb → search → bell → shortcuts → avatar. */
  .nv2-topbar-search { order: 9; flex: 1 0 100%; margin-left: 0; }
  .nv2-content { padding: 14px 12px 48px; }
}


/* ─── HUB-TASKFIRST (2026-09-04) — the Remittance hub's task-first menu ─────
   A GROUP renders through the existing .nv2-module chrome; what is new is the
   ENTRY row — a page, and nothing but its name. Every rule below is a NEW
   class — nothing existing is redefined, so the other seven hubs render
   byte-identically.

   HUBFIX-4 (2026-09-04, owner ruling on staging deploy #31): the explanatory
   one-liners are gone from the rail. "Why does it have text like 'Your inbox',
   'today's picture', 'transactions, customers, beneficiaries and complaints' —
   these do not need to be here, they make it more confusing." So
   .nv2-module-hint, .nv2-entry-hint and the whole HUBFIX-2 `.has-hint` wrap
   block are REMOVED rather than left dead in the sheet — the same treatment
   HUBFIX-3 gave the views chip, and for the same reason: a rule with no markup
   is an invitation to bring the markup back. A group button is now the name,
   the count and the chevron on one line, for all eight hubs alike. */

.nv2-entry { list-style: none; display: block; }
/* HUBFIX-1: the row owns the whole column, so the name gets every pixel the
   badge and the pin star do not, and the hover/active highlight spans the row
   instead of stopping at the end of the text. */
.nv2-entry-row { display: flex; align-items: center; gap: 6px; width: 100%; min-width: 0; }
/* The entry's own link uses the leaf typography and indent so an entry and a
   view row line up with the classic rail. */
.nv2-module-children li.nv2-entry .nv2-entry-head {
  display: flex; align-items: center; gap: 8px;
  flex: 1 1 auto; min-width: 0;
  padding: 6px 12px 6px 38px; margin: 0 0 0 4px;
  font-size: 13px; color: var(--nv2-ink-2);
  text-decoration: none; border-radius: 6px;
  transition: all 120ms ease;
  /* HUBFIX-1: the mock-up shows full names. A name too long for the column
     wraps onto a second line; it is never truncated and never cut mid-word. */
  white-space: normal; overflow-wrap: break-word; line-height: 1.3;
}
.nv2-module-children li.nv2-entry a.nv2-entry-head:hover { background: var(--nv2-panel-2); color: var(--nv2-ink); }
.nv2-module-children li.nv2-entry a.nv2-entry-head.is-active {
  background: var(--nv2-hub-accent, var(--nv2-brand));
  color: white; font-weight: 600;
}
/* An entry whose own row the RBAC filters removed but whose views survived: a
   header for them, deliberately not a link (the sub-group behaviour of today). */
.nv2-module-children li.nv2-entry .nv2-entry-head.is-header {
  color: var(--nv2-ink-3); font-weight: 600; cursor: default;
}

/* HUBFIX-4: the entry's one hint line is gone with the group's — see the block
   comment at the head of this section. Text diet: names only, never prose. */

/* The operator's own open Action Centre backlog — the SAME number the rail pill
   shows (root loader navBadges), never a second query. */
.nv2-entry-badge {
  flex: 0 0 auto;
  background: var(--nv2-accent); color: white;
  font-size: 10px; font-weight: 700;
  padding: 1px 6px; border-radius: 999px;
}

/* HUBFIX-3 (2026-09-04, owner ruling): the "N views" chip and the fly-out it
   opened are gone — one row per page. The query-string views are the PAGE's
   own tab row now, so .nv2-views-chip / .nv2-entry-views no longer render and
   their rules are removed rather than left dead in the sheet. */

/* ── Phone (SHELL-RESP-1 drawer, <=1200px): the fourth level has to give back
      its indent or a 300px drawer wraps every label onto two lines. ────────── */
@media (max-width: 1200px) {
  .nv2-module-children li.nv2-entry .nv2-entry-head { padding-left: 26px; }
  /* HUBFIX-4: the two hint rules that lived here (the entry hint's narrow
     indent and `display: none` on the group hint, which was the phone's way of
     keeping the count on the row) are gone with the hints themselves. */
}

/* -- "Today" strip on the Remittance 360 Dashboard -------------------- */
.rem-d-today { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 10px; }
.rem-d-today-tile {
  display: flex; flex-direction: column; gap: 2px; min-width: 0;
  background: #fff; border: 1px solid var(--nv2-line-2, #e4e9f2); border-radius: 12px;
  box-shadow: 0 3px 12px rgba(26, 42, 74, 0.035); padding: 10px 12px;
  text-decoration: none; color: inherit;
}
.rem-d-today-tile:hover { border-color: #2f6fed; }
.rem-d-today-tile:focus-visible { outline: 2px solid #2f6fed; outline-offset: 2px; }
.rem-d-today-value { font-size: 1.3rem; line-height: 1.15; font-weight: 850; color: var(--nv2-ink); }
.rem-d-today-label { font-size: 0.78rem; font-weight: 750; color: var(--nv2-ink-2); }
.rem-d-today-sub {
  font-size: 0.7rem; color: var(--nv2-ink-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
@media (max-width: 1100px) {
  .rem-d-today { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 620px) {
  .rem-d-today { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
/* ── HUB-TASKFIRST/A — the transition dot ──────────────────────────────────
   One 6px dot on each of the TEN rows PR #533 renamed, until this browser has
   opened that row once (shell.jsx, localStorage 'nv2.seenRenames'). The name it
   replaced rides the title + aria-label; the dot itself carries no text, which
   is what keeps the menu to names + one hint line. */
.nv2-rename-dot {
  flex: 0 0 auto;
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--nv2-hub-accent, var(--nv2-brand));
  /* Not a decoration on the label: it sits in the row's flex flow so a wrapped
     phone row keeps it beside the name it belongs to. */
  align-self: center;
}
/* Inside a view row the dot follows the link, which is the flex item, so it
   needs the same vertical rhythm as the leaf text next to it. */
.nv2-module-children li > .nv2-rename-dot { margin-left: -4px; }

/* ── HUB-TASKFIRST/B — keyboard reachability ───────────────────────────────
   Two things, both additive (no existing rule is redefined).

   1. A COLLAPSED region was still in the tab order. `.nv2-module-children`,
      `.nv2-subgroup-children` close with
      `max-height: 0; overflow: hidden`, which CLIPS their rows but leaves every
      link focusable and in the accessibility tree — so tabbing through the
      Remittance panel walked all 91 entries of nine closed groups before
      reaching the page. `visibility: hidden` is what actually
      takes them out, and it is delayed by the same duration as the height so
      the open/close animation still plays (the drawer above uses the identical
      trick). The nested pair at the end covers the one state the accordion can
      produce on its own: a sub-group left open inside a group the operator then
      closed.
   2. Every menu control gets a visible focus ring. Keyboard operation you
      cannot SEE is not keyboard operation. :focus-visible only, so a mouse
      click never draws one. */

.nv2-module-children:not(.is-open),
.nv2-subgroup-children:not(.is-open) {
  visibility: hidden;
  transition-property: max-height, visibility;
  transition-delay: 0s, 320ms;
}
.nv2-module-children.is-open,
.nv2-subgroup-children.is-open {
  visibility: visible;
  transition-delay: 0s, 0s;
}
/* A closed group hides what is inside it, however its own children are marked. */
.nv2-module-children:not(.is-open) .nv2-subgroup-children { visibility: hidden; }

.nv2-hub-list :focus-visible,
.nv2-hub-panel :focus-visible {
  outline: 2px solid var(--nv2-hub-accent, var(--nv2-brand));
  outline-offset: 1px;
  border-radius: 6px;
}
/* The rail's own controls, which the drawer puts on the same keyboard path. */
.nv2-hub-btn:focus-visible,
.nv2-rail-pin:focus-visible,
.nv2-nav-close:focus-visible {
  outline: 2px solid var(--nv2-brand);
  outline-offset: -2px;
}
/* The header entry is an arrow-key destination but never a Tab stop, so its
   ring must still be visible when the arrows put focus on it. */
.nv2-entry-head.is-header:focus-visible {
  outline: 2px solid var(--nv2-hub-accent, var(--nv2-brand));
  outline-offset: 1px;
}

/* ── HUB-TASKFIRST/C — the four-level tree on a phone ──────────────────────
   At <=900px the SHELL-RESP-1 drawer is `min(100vw - 40px, 350px)` wide and
   the rail takes a fixed 80px of it, so on a 390px handset the hub panel gets
   270px and the list itself 250px of usable width. Four levels of the shipped
   desktop indent (group 12px, section 38px, entry 38px, view 54px) spend 54 of
   those 250 on whitespace before the first letter of a view row.

   CSS only; nothing here exists above 900px, so the desktop menu is untouched.
   Every rule is additive — no desktop declaration is redefined. */
@media (max-width: 900px) {
  /* Nothing in the menu may push the drawer sideways. */
  .nv2-shell-nav .nv2-hub-panel-col,
  .nv2-shell-nav .nv2-hub-list { overflow-x: hidden; }
  .nv2-shell-nav .nv2-hub-list { padding-left: 4px; padding-right: 6px; }

  /* GROUP. The name may take two lines rather than lose its tail; the count
     and the chevron stay pinned to the top line where the eye expects them. */
  .nv2-shell-nav .nv2-module-btn { align-items: flex-start; padding: 8px; gap: 8px; }
  .nv2-shell-nav .nv2-module-btn > span {
    min-width: 0; overflow-wrap: break-word; line-height: 1.3;
  }
  .nv2-shell-nav .nv2-module-btn .nv2-count,
  .nv2-shell-nav .nv2-module-btn .nv2-chev,
  .nv2-shell-nav .nv2-module-btn .nv2-icon { margin-top: 1px; }

  /* SECTION. 38px of indent buys nothing at this width; 22px still reads as
     one level in from the group. */
  .nv2-shell-nav .nv2-subgroup-btn {
    padding-left: 22px; align-items: flex-start;
  }
  .nv2-shell-nav .nv2-subgroup-btn > span:first-child {
    min-width: 0; overflow-wrap: break-word; line-height: 1.3;
  }

  /* ENTRY. Two distinct, legible steps — 22 / 34 — instead of 38 / 54. The
     entry keeps at least 58% of the row, so a long name WRAPS and the badge
     and pin star fall to a second line rather than squeezing the name into a
     two-character column. */
  .nv2-shell-nav .nv2-entry-row { flex-wrap: wrap; row-gap: 2px; }
  .nv2-shell-nav .nv2-module-children li.nv2-entry .nv2-entry-head {
    padding-left: 22px; padding-right: 8px;
    min-width: 58%;
    white-space: normal; overflow-wrap: break-word; line-height: 1.3;
  }
  .nv2-shell-nav .nv2-module-children li a,
  .nv2-shell-nav .nv2-module-children li > span {
    padding-left: 22px; padding-right: 8px;
    white-space: normal; overflow-wrap: break-word; line-height: 1.3;
  }
  .nv2-shell-nav .nv2-subgroup-children li a { padding-left: 34px; }

  /* HUBFIX-4: the drawer's hint-wrapping rule is gone with the hints. At 390px
     the accordion is now group name → page names, with nothing between them. */

  /* Wrapped rows are taller than the desktop ones the max-height ceilings were
     measured against, and a ceiling that is too low CLIPS the bottom of an open
     group with no scrollbar to reveal it. */
  .nv2-shell-nav .nv2-module-children.is-open { max-height: 6000px; }
  .nv2-shell-nav .nv2-subgroup-children.is-open { max-height: 2400px; }
}

/* ── HUB-TASKFIRST/D — the group's own activity roll-up ────────────────────
   The SAME number the Action Centre entry carries (root loader navBadges),
   re-shown on the group that contains it while that group is CLOSED and hiding
   it. Deliberately quieter than the entry badge it mirrors — it is a signpost
   to a row, not a second count — and it never appears where no badge exists. */
.nv2-module-btn .nv2-group-activity {
  flex: 0 0 auto;
  margin-left: auto;
  background: var(--nv2-accent); color: white;
  font-size: 10px; font-weight: 700; line-height: 1.6;
  padding: 0 6px; border-radius: 999px;
}
/* The count pill already claims `margin-left: auto`; with the roll-up present
   the roll-up is the one that pushes, and the count follows it. */
.nv2-module-btn .nv2-group-activity ~ .nv2-count { margin-left: 6px; }

/* -- Finance hub (build/finance-hub) -- page header + tab strip ---------------
   The Finance rail is 31 rows over 12 groups (app/config/finance-hub.js); the
   pages those rows carry are TABS on the page that owns them, rendered by
   components/v2/new/FinancePageHeader.jsx above the route's own body. That is the
   owner's "filters are tabs on the page" rule made visible.

   THE STRIP REUSES .nv2-tab-bar / .nv2-tab AND DEFINES NO SECOND TAB DESIGN.
   The first draft of this block invented .nv2-tabstrip and its own .nv2-tab rules,
   and both were wrong in ways only a rendered page would have shown:
     * `.nv2-tab` ALREADY EXISTS (line ~1052, the v2 TabBar in components/v2/new/
       data.jsx). A bare `.nv2-tab.is-active::after` draws a 3px underline, so the
       draft's own `border-bottom: 2px` gave the active tab TWO underlines.
     * the draft styled itself with --nv2-text / --nv2-text-muted / --nv2-border /
       --nv2-surface-2, and NONE of those tokens exists in this sheet. Every one
       would have fallen through to its hard-coded hex, so the strip would have
       ignored the theme and the hub accent entirely.
   Reusing the component's classes means one tab design, themed, already
   responsive, and nothing here to keep in step with it.

   The only additions are the page head and the two things a LINK needs that a
   BUTTON did not.
   MIRRORED: app/components/v2/tokens.css is the source and
   public/styles/v2-tokens.css is what the browser loads. Change BOTH and bump
   NV2_TOKENS_VERSION in app/root.jsx, or the change ships nothing. */
.nv2-finhead { margin: 0 0 18px; }
/* An EYEBROW, not a title: 18 of the hub's pages carry their own heading, and a
   row label at title weight above one of those named the page twice (F-9). Small,
   muted, uppercase — it says which ROW you are on, and leaves the page's own
   heading as the page's heading. */
.nv2-finhead .nv2-fineyebrow {
  margin: 0 0 2px; font-size: 11px; line-height: 1.4; font-weight: 600;
  letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--nv2-ink-3);
}
/* The ONE consequence line, beside the control it describes and never in the
   rail (owner ruling 2026-09-05 13:48Z). Capped so it cannot grow into prose. */
.nv2-finhead .nv2-finline {
  margin: 6px 0 0; font-size: 13px; line-height: 1.45;
  color: var(--nv2-ink-2); max-width: 76ch;
}
.nv2-finhead .nv2-tab-bar { margin-top: 14px; }
/* A tab is a <Link>, not the <button> .nv2-tab was written for. */
.nv2-finhead a.nv2-tab { text-decoration: none; }
/* A switched-off module's page still renders for SUPER_ADMIN, carrying its state
   as a label rather than being silently absent (owner ruling 2026-09-05 13:11Z). */
.nv2-finhead a.nv2-tab.is-off { opacity: 0.65; }
.nv2-finhead .nv2-fintab-off { font-size: 11px; font-weight: 500; color: var(--nv2-ink-3); }
/* ── FINANCE HUB page header + tab strip (2026-09-05, build/finance-hub) ─────
   The Finance rail is 30 rows over 11 groups (app/config/finance-hub.js); the 67
   pages those rows carry are TABS on the page that owns them, rendered here by
   components/v2/new/FinancePageHeader.jsx above the route's own body. The strip
   is the owner's "filters are tabs on the page" rule made visible, so it must
   read as part of the page and never as a second rail.
   ⚠ THIS BLOCK IS MIRRORED: app/components/v2/tokens.css is the source and
   public/styles/v2-tokens.css is what the browser loads. Change BOTH and bump
   NV2_TOKENS_VERSION in app/root.jsx, or the change ships nothing. */
.nv2-page-head { margin: 0 0 18px; }
.nv2-page-title {
  margin: 0; font-size: 20px; line-height: 1.25; font-weight: 650;
  color: var(--nv2-text, #0f172a); letter-spacing: -0.01em;
}
.nv2-page-consequence {
  margin: 6px 0 0; font-size: 13px; line-height: 1.45;
  color: var(--nv2-text-muted, #64748b); max-width: 76ch;
}
.nv2-tabstrip {
  display: flex; flex-wrap: wrap; gap: 2px; margin: 14px 0 0;
  border-bottom: 1px solid var(--nv2-border, #e2e8f0);
}
.nv2-tabstrip .nv2-tab {
  display: inline-block; padding: 8px 12px; font-size: 13px; font-weight: 500;
  color: var(--nv2-text-muted, #64748b); text-decoration: none;
  border-bottom: 2px solid transparent; margin-bottom: -1px; white-space: nowrap;
  border-radius: 6px 6px 0 0;
}
.nv2-tabstrip .nv2-tab:hover { color: var(--nv2-text, #0f172a); background: var(--nv2-surface-2, #f8fafc); }
.nv2-tabstrip .nv2-tab.is-active {
  color: var(--nv2-accent, #0ea5e9); border-bottom-color: var(--nv2-accent, #0ea5e9); font-weight: 600;
}
/* A switched-off module's page still renders for SUPER_ADMIN, carrying its state
   as a label rather than being silently absent (owner ruling 2026-09-05 13:11Z). */
.nv2-tabstrip .nv2-tab.is-off { opacity: 0.65; }
.nv2-tabstrip .nv2-tab-off { font-size: 11px; font-weight: 500; color: var(--nv2-text-muted, #64748b); }
@media (max-width: 720px) {
  .nv2-tabstrip { flex-wrap: nowrap; overflow-x: auto; }
}

/* ── ADMIN & PLATFORM HUB — the SECOND consumer of the strip above ───────────
   build/admin-hub folds the Admin & Platform rail from 69 rows over 10 modules to
   26 rows over 6 groups (app/config/admin-hub.js) and renders the pages those rows
   carry as tabs, through components/v2/new/AdminPageHeader.jsx. It reuses the
   classes above verbatim rather than defining a second look: two hubs whose tab
   strips did not match would read as two products.
   ⚠ DO NOT 'CORRECT' THE FINANCE-ONLY WORDING OF THE BLOCK ABOVE IN A SWEEP — it
   is byte-identical to the copy on build/finance-hub on purpose, so the conductor's
   merge of the two hub branches is one block and not a conflict.
   ⚠ THIS BLOCK IS MIRRORED: app/components/v2/tokens.css is the source and
   public/styles/v2-tokens.css is what the browser loads. Change BOTH and bump
   NV2_TOKENS_VERSION in app/root.jsx, or the change ships nothing. */
.nv2-page-head[data-admin-row] .nv2-tabstrip { margin-top: 12px; }
/* ── HUB page header + tab strip (2026-09-05, build/agents-hub) ──────────────
   The Branches & Partners rail is 25 rows over 6 groups (app/config/agents-hub.js);
   the pages those rows carry are TABS on the page that owns them, rendered by
   components/v2/new/AgentsPageHeader.jsx (and Branch360Tabs.jsx on the nine
   per-branch doors) above the route's own body. The strip is the owner's "filters
   are tabs on the page" rule made visible, so it must read as part of the page and
   never as a second rail.
   ⚠ THIS BLOCK IS MIRRORED: app/components/v2/tokens.css is the source and
   public/styles/v2-tokens.css is what the browser loads. Change BOTH and bump
   NV2_TOKENS_VERSION in app/root.jsx, or the change ships nothing.
   ⚠ CONDUCTOR: build/finance-hub adds a block with the SAME SELECTORS and the same
   declarations for its own strip. On the merge KEEP EITHER ONE, NEVER BOTH — two
   copies of these selectors is a duplicate, not a conflict resolved. */
.nv2-page-head { margin: 0 0 18px; }
.nv2-page-title {
  margin: 0; font-size: 20px; line-height: 1.25; font-weight: 650;
  color: var(--nv2-text, #0f172a); letter-spacing: -0.01em;
}
.nv2-page-consequence {
  margin: 6px 0 0; font-size: 13px; line-height: 1.45;
  color: var(--nv2-text-muted, #64748b); max-width: 76ch;
}
.nv2-tabstrip {
  display: flex; flex-wrap: wrap; gap: 2px; margin: 14px 0 0;
  border-bottom: 1px solid var(--nv2-border, #e2e8f0);
}
.nv2-tabstrip .nv2-tab {
  display: inline-block; padding: 8px 12px; font-size: 13px; font-weight: 500;
  color: var(--nv2-text-muted, #64748b); text-decoration: none;
  border-bottom: 2px solid transparent; margin-bottom: -1px; white-space: nowrap;
  border-radius: 6px 6px 0 0;
}
.nv2-tabstrip .nv2-tab:hover { color: var(--nv2-text, #0f172a); background: var(--nv2-surface-2, #f8fafc); }
.nv2-tabstrip .nv2-tab.is-active {
  color: var(--nv2-accent, #0ea5e9); border-bottom-color: var(--nv2-accent, #0ea5e9); font-weight: 600;
}
/* A switched-off module's page still renders for SUPER_ADMIN, carrying its state
   as a label rather than being silently absent (owner ruling 2026-09-05 13:11Z). */
.nv2-tabstrip .nv2-tab.is-off { opacity: 0.65; }
.nv2-tabstrip .nv2-tab-off { font-size: 11px; font-weight: 500; color: var(--nv2-text-muted, #64748b); }
@media (max-width: 720px) {
  .nv2-tabstrip { flex-wrap: nowrap; overflow-x: auto; }
}
/* ── FINANCE HUB page header + tab strip (2026-09-05, build/finance-hub) ─────
   The Finance rail is 30 rows over 11 groups (app/config/finance-hub.js); the 67
   pages those rows carry are TABS on the page that owns them, rendered here by
   components/v2/new/FinancePageHeader.jsx above the route's own body. The strip
   is the owner's "filters are tabs on the page" rule made visible, so it must
   read as part of the page and never as a second rail.
   ⚠ THIS BLOCK IS MIRRORED: app/components/v2/tokens.css is the source and
   public/styles/v2-tokens.css is what the browser loads. Change BOTH and bump
   NV2_TOKENS_VERSION in app/root.jsx, or the change ships nothing. */
.nv2-page-head { margin: 0 0 18px; }
.nv2-page-title {
  margin: 0; font-size: 20px; line-height: 1.25; font-weight: 650;
  color: var(--nv2-text, #0f172a); letter-spacing: -0.01em;
}
.nv2-page-consequence {
  margin: 6px 0 0; font-size: 13px; line-height: 1.45;
  color: var(--nv2-text-muted, #64748b); max-width: 76ch;
}
.nv2-tabstrip {
  display: flex; flex-wrap: wrap; gap: 2px; margin: 14px 0 0;
  border-bottom: 1px solid var(--nv2-border, #e2e8f0);
}
.nv2-tabstrip .nv2-tab {
  display: inline-block; padding: 8px 12px; font-size: 13px; font-weight: 500;
  color: var(--nv2-text-muted, #64748b); text-decoration: none;
  border-bottom: 2px solid transparent; margin-bottom: -1px; white-space: nowrap;
  border-radius: 6px 6px 0 0;
}
.nv2-tabstrip .nv2-tab:hover { color: var(--nv2-text, #0f172a); background: var(--nv2-surface-2, #f8fafc); }
.nv2-tabstrip .nv2-tab.is-active {
  color: var(--nv2-accent, #0ea5e9); border-bottom-color: var(--nv2-accent, #0ea5e9); font-weight: 600;
}
/* A switched-off module's page still renders for SUPER_ADMIN, carrying its state
   as a label rather than being silently absent (owner ruling 2026-09-05 13:11Z). */
.nv2-tabstrip .nv2-tab.is-off { opacity: 0.65; }
.nv2-tabstrip .nv2-tab-off { font-size: 11px; font-weight: 500; color: var(--nv2-text-muted, #64748b); }
@media (max-width: 720px) {
  .nv2-tabstrip { flex-wrap: nowrap; overflow-x: auto; }
}
/* ══════════════ Compliance hub (build/compliance-hub) — the tab strip ═══════
   Drawn ONCE by shell.jsx above `{children}`, for the 25 folded rows of the
   Compliance & Regulatory hub. It carries a row label and its tabs, and nothing
   else: no note, no rule text, no consequence line (owner, 2026-09-05 15:58Z).

   ⚠ THIS BLOCK IS MIRRORED. `app/components/v2/tokens.css` is the source and
   `public/styles/v2-tokens.css` is what the browser actually loads, and the
   mirror is maintained BY HAND. A rule added to one only ships nothing, in
   silence. Both files carry this block byte-for-byte, and NV2_TOKENS_VERSION in
   app/root.jsx is bumped with it or the 1-hour cache pins the old sheet. */
.nv2-cphub-head {
  display: flex; align-items: center; flex-wrap: wrap;
  gap: 4px 16px;
  padding: 0 0 10px;
  margin: 0 0 14px;
  border-bottom: 1px solid var(--nv2-border, #e5e7eb);
}
.nv2-cphub-row {
  font-size: 15px; font-weight: 650; line-height: 1.4;
  color: var(--nv2-fg, #111827);
}
/* Horizontal scroll rather than a wrap-to-three-lines strip: the PSR row folds
   eleven tabs and the GDPR row ten, and a strip that reflows moves the tab under
   the operator's cursor when the window changes. */
.nv2-cphub-tabs {
  display: flex; align-items: center; gap: 2px;
  overflow-x: auto; max-width: 100%;
  padding-bottom: 10px;
  scrollbar-width: thin;
  scrollbar-color: var(--nv2-line, #e5e7eb) transparent;
}
.nv2-cphub-tabs::-webkit-scrollbar { height: 6px; }
.nv2-cphub-tabs::-webkit-scrollbar-track { background: transparent; margin: 0 4px; }
.nv2-cphub-tabs::-webkit-scrollbar-thumb {
  background: var(--nv2-line, #e5e7eb);
  border-radius: 999px;
}
.nv2-cphub-tabs:hover::-webkit-scrollbar-thumb { background: var(--nv2-ink-3, #9ca3af); }
.nv2-cphub-tabs::-webkit-scrollbar-thumb:hover { background: var(--nv2-accent, #ec4899); }
.nv2-cphub-tab {
  flex: 0 0 auto;
  padding: 5px 10px;
  border-radius: 6px;
  font-size: 13px; line-height: 1.4;
  color: var(--nv2-fg-muted, #6b7280);
  text-decoration: none;
  white-space: nowrap;
}
.nv2-cphub-tab:hover { background: var(--nv2-surface-2, #f3f4f6); color: var(--nv2-fg, #111827); }
.nv2-cphub-tab.is-active {
  background: var(--nv2-surface-2, #f3f4f6);
  color: var(--nv2-fg, #111827);
  font-weight: 600;
  box-shadow: inset 0 -2px 0 0 var(--nv2-accent, #ec4899);
}
.nv2-cphub-tab:focus-visible { outline: 2px solid var(--nv2-accent, #ec4899); outline-offset: 1px; }
/* SHELL-RESP-1: below the drawer breakpoint the strip is the only horizontal
   scroller on the page; the document itself must never scroll sideways. */
@media (max-width: 1200px) {
  .nv2-cphub-head { gap: 4px 10px; }
  .nv2-cphub-tab { padding: 5px 8px; font-size: 12px; }
}

/* SETUP WIZARD SHELL (2026-09-06) — A COUNTED LEAF ROW IS A FLEX ROW, PINNABLE OR NOT.
   Measured on the swz rig (shots-setup-wizard-shell/16-rail-setup-row.png, the DOM dump in
   SETUP-WIZARD-SHELL-REPORT.md §6): with the pins cache cold the <li> carried no class, so the
   HUBFIX-1 flex rule above did not apply, the active <a> (display:flex, full width) took the
   line and the row's own count pill — a bare `.nv2-count` span with no leaf-level styling —
   wrapped UNDER the link as the naked text "21". The rail's law is label + count on one row.
   `li.nv2-leaf-counted` is set by shell.jsx#leafLi whenever hub.rowBadges carries the row. */
.nv2-hub-panel li.nv2-leaf-counted:not(.nv2-entry) { display: flex; align-items: center; }
.nv2-hub-panel li.nv2-leaf-counted > a,
.nv2-hub-panel li.nv2-leaf-counted > span:not(.nv2-count) { flex: 1 1 auto; min-width: 0; }
.nv2-hub-panel li.nv2-leaf-counted > .nv2-count {
  font-size: 11px; font-weight: 600;
  color: var(--nv2-ink-3);
  background: var(--nv2-bg);
  padding: 1px 7px;
  border-radius: 999px;
  margin-left: 6px;
  white-space: nowrap;
  flex: 0 0 auto;
  box-sizing: border-box;
  min-width: 28px;
  text-align: center;
}

/* ─────────────────────────────────────────────────────────────────────────────
   x360 — the shared 360 family (360-BUILD-CONTRACT §1). Structure only: the v2
   SKIN lands over these class names, so nothing here paints beyond the tokens
   the rest of this sheet already publishes.
   ───────────────────────────────────────────────────────────────────────────── */
.x360-tone-ok    { --x360-tone: var(--nv2-success, #15803d); }
.x360-tone-info  { --x360-tone: var(--nv2-info, #1d4ed8); }
.x360-tone-warn  { --x360-tone: var(--nv2-warning, #b45309); }
.x360-tone-bad   { --x360-tone: var(--nv2-danger, #b91c1c); }
.x360-tone-grey  { --x360-tone: var(--nv2-text-muted, #64748b); }

.x360-header { display: flex; flex-direction: column; gap: 10px; padding: 14px 16px;
  background: var(--nv2-surface, #fff); border: 1px solid var(--nv2-border, #e2e8f0); border-radius: 10px; }
.x360-header-eyebrow { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.x360-header-updated { font-size: 12px; color: var(--nv2-text-muted, #64748b); }
.x360-header-main { display: flex; gap: 24px; flex-wrap: wrap; justify-content: space-between; }
.x360-header-left { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; min-width: 260px; }
.x360-header-title { font-size: 20px; font-weight: 700; margin: 0; }
.x360-code { font-size: 12px; padding: 2px 8px; border-radius: 999px; border: 1px solid var(--nv2-border, #e2e8f0); }
.x360-header-right { display: flex; flex-direction: column; gap: 8px; align-items: flex-end; }
.x360-header-stop { display: flex; }
.x360-header-held { margin: 0; font-size: 13px; color: var(--nv2-warning, #b45309); }
.x360-pill { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 600;
  padding: 2px 10px; border-radius: 999px; color: var(--x360-tone, #64748b);
  border: 1px solid currentColor; background: transparent; }
.x360-identity, .x360-facts { display: flex; gap: 18px; flex-wrap: wrap; margin: 0; }
/* THE `div` ARM IS FOR A BARE dt/dd ROW, AND ONLY FOR THAT (Account Settings build,
   2026-09-07). This block predates `app/styles/x360.css` — the approved skin the four
   360 record pages and Account Settings actually wear — and was written for a `<dl>`
   whose rows are an UNCLASSED `div` wrapping a `dt` and a `dd`. The shipped components
   render `.x360-identity` and `.x360-facts` with CLASSED divs instead (`x360-idbody`,
   `x360-nameline`, `x360-stateline`, `x360-fact`, `.k` / `.v` / `.s`), and
   `.x360-identity div` is (0,1,1) — it out-specifies every one of the skin's
   single-class rules, so it won `flex-direction` on all of them.

   MEASURED on the engine rig, SUPER_ADMIN, 1440, BEFORE this line changed:
     /agents/<id>  (Branch 360, shipped)   .x360-nameline  flex-direction: column,
                                           align-items: center  →  the branch's NAME
                                           rendered centred at x=780 inside a container
                                           starting at x=485
     /remittance/transactions/<id>/360     .x360-fact .v    flex-direction: column,
                                           align-items: center  →  every header FIGURE
                                           centred in its cell instead of reading left
   A column flex whose `align-items: center` comes from the skin centres its children
   horizontally; that pair is the whole defect, and neither sheet is wrong on its own.

   `:not([class])` keeps the rule for the shape it was written for and takes it off
   every shape it was not. The tree contains ZERO `<dt>` under either class today
   (grepped), so the kept arm is inert and the removed one is the live defect. */
.x360-identity div:not([class]), .x360-facts div:not([class]) { display: flex; flex-direction: column; }
.x360-identity dt, .x360-facts dt { font-size: 11px; text-transform: uppercase; letter-spacing: .04em; color: var(--nv2-text-muted, #64748b); }
.x360-identity dd, .x360-facts dd { margin: 0; font-size: 13px; font-weight: 600; font-variant-numeric: tabular-nums; }
.x360-reveal { margin-left: 8px; font-weight: 500; font-size: 12px; }

.x360-tiles { display: flex; flex-wrap: wrap; gap: 10px; }
.x360-tile { flex: 1 1 190px; min-width: 170px; display: flex; flex-direction: column; gap: 2px;
  padding: 10px 12px; text-align: left; background: var(--nv2-surface, #fff);
  border: 1px solid var(--nv2-border, #e2e8f0); border-radius: 10px; cursor: pointer; }
.x360-tile-label { font-size: 11px; text-transform: uppercase; letter-spacing: .04em; color: var(--nv2-text-muted, #64748b); }
.x360-tile-value { font-size: 18px; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--x360-tone, inherit); }
.x360-tile-sub { font-size: 12px; color: var(--nv2-text-muted, #64748b); }

.x360-tabstrip { width: 100%; }
.x360-tabstrip-row { display: flex; align-items: center; gap: 6px; flex-wrap: nowrap; }
.x360-tab { white-space: nowrap; border: 1px solid transparent; background: transparent; cursor: pointer;
  padding: 7px 12px; border-radius: 8px 8px 0 0; font-size: 13px; font-weight: 600; color: var(--nv2-text-muted, #64748b); }
.x360-tab.is-active { color: var(--nv2-text, #0f172a); border-color: var(--nv2-border, #e2e8f0); border-bottom-color: transparent; background: var(--nv2-surface, #fff); }
.x360-tab-count { margin-left: 6px; font-size: 11px; padding: 0 6px; border-radius: 999px; background: var(--nv2-surface-alt, #f1f5f9); }
.x360-more { position: relative; }
.x360-more-menu { position: absolute; right: 0; top: 100%; z-index: 40; min-width: 200px; padding: 6px;
  background: var(--nv2-surface, #fff); border: 1px solid var(--nv2-border, #e2e8f0); border-radius: 8px;
  box-shadow: 0 12px 30px rgba(15, 23, 42, .16); display: flex; flex-direction: column; }
.x360-more-item { text-align: left; background: transparent; border: 0; cursor: pointer; padding: 7px 10px; border-radius: 6px; font-size: 13px; }
.x360-more-item:hover { background: var(--nv2-surface-alt, #f1f5f9); }

.x360-panel { padding: 12px 14px; background: var(--nv2-surface, #fff);
  border: 1px solid var(--nv2-border, #e2e8f0); border-radius: 10px; }
.x360-panel-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.x360-panel-title { margin: 0 0 8px; font-size: 14px; font-weight: 700; }
.x360-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 6px 22px; margin: 0; }
.x360-row { display: flex; justify-content: space-between; gap: 14px; padding: 4px 0; border-bottom: 1px dashed var(--nv2-border, #e2e8f0); }
.x360-row dt { font-size: 12px; color: var(--nv2-text-muted, #64748b); }
.x360-row dd { margin: 0; font-size: 13px; font-weight: 600; text-align: right; font-variant-numeric: tabular-nums; color: var(--x360-tone, inherit); }
.x360-sub { display: block; font-size: 11px; font-weight: 400; color: var(--nv2-text-muted, #64748b); }
.x360-empty, .x360-unreadable { margin: 4px 0 0; font-size: 13px; }
.x360-unreadable { color: var(--nv2-warning, #b45309); font-weight: 600; }
.x360-consequence { margin: 8px 0 0; font-size: 12px; color: var(--nv2-text-muted, #64748b); }
.x360-table-wrap { overflow-x: auto; }
.x360-table { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.x360-table th, .x360-table td { text-align: left; padding: 6px 8px; border-bottom: 1px solid var(--nv2-border, #e2e8f0); }
.x360-table th { font-size: 11px; text-transform: uppercase; letter-spacing: .04em; color: var(--nv2-text-muted, #64748b); }
.x360-table td.is-right, .x360-table th.is-right { text-align: right; font-variant-numeric: tabular-nums; }

/* THE PRE-SKIN DOORS BLOCK, NARROWED TO THE MARKUP IT WAS WRITTEN FOR (2026-09-07).
   Same defect and same remedy as `.x360-identity div` twelve lines above. This block
   predates `app/styles/x360.css` (the approved skin the four 360 record pages wear) and
   was written for a doors row whose children were `.x360-doors-group` rows, each holding
   a `.x360-doors-group-name` and a `.x360-doors-list`. `DoorsRow.jsx` renders NONE of
   those class names today (grepped: zero elements carry them anywhere in the tree), but
   it does render `.x360-doors` and `.x360-door` - so this rule's `flex-direction: column`
   reached the shipped row. The skin declared `display`, `flex-wrap` and `align-items` on
   `.x360-doors` and NOT `flex-direction`, which left this declaration UNCONTESTED at any
   cascade order; the skin's own `align-items: center` then centred every child of the
   column it had been turned into.
   MEASURED on two engine rigs, SUPER_ADMIN, 1440, /agents/<id> (Branch 360), BEFORE this
   change: `.x360-doors` computed `flex-direction: column; align-items: center`, the six
   category groups stacked as six centred rows with ragged left edges, and `.x360-door`
   computed `flex-direction: column` so a gated door stacked its "1 person" badge under its
   label - two door heights in one row (57 px and 32 px). Identical at 61abf7b49 (deploy
   #60) and 1ce84aa24 (deploy #74), so this was never a regression of a later commit.
   `:has(> .x360-doors-group)` / `:has(> .x360-door-head)` keep each rule for the shape it
   was written for and take it off the shape it was not; both arms are inert today, exactly
   like the kept `dt`/`dd` arm above. The skin now declares `flex-flow: row wrap` itself and
   `tests/x360-doors-row-owns-its-layout.test.js` fails if either half of that pair moves. */
.x360-doors:has(> .x360-doors-group) { display: flex; flex-direction: column; gap: 8px; }
.x360-doors-group { display: flex; gap: 10px; align-items: flex-start; flex-wrap: wrap; }
.x360-doors-group-name { min-width: 92px; font-size: 11px; text-transform: uppercase; letter-spacing: .04em;
  color: var(--nv2-text-muted, #64748b); padding-top: 7px; }
.x360-doors-list { display: flex; gap: 8px; flex-wrap: wrap; }
.x360-door:has(> .x360-door-head) { display: flex; flex-direction: column; gap: 2px; }
.x360-door-head { display: inline-flex; align-items: center; gap: 6px; }
.x360-door-btn { display: inline-flex; align-items: center; padding: 6px 12px; font-size: 13px; font-weight: 600;
  border-radius: 8px; border: 1px solid var(--nv2-border, #e2e8f0); background: var(--nv2-surface, #fff); cursor: pointer; }
.x360-door-btn[disabled] { cursor: not-allowed; opacity: .55; }
.x360-door-why { width: 18px; height: 18px; line-height: 1; border-radius: 999px; cursor: pointer;
  border: 1px solid var(--nv2-border, #e2e8f0); background: transparent; font-size: 11px; color: var(--nv2-text-muted, #64748b); }
.x360-door-pop { margin: 2px 0 0; max-width: 380px; font-size: 12px; color: var(--nv2-text-muted, #64748b); }
.x360-door-refused { margin: 2px 0 0; max-width: 380px; font-size: 12px; color: var(--nv2-warning, #b45309); }
.x360-badge { font-size: 10.5px; font-weight: 700; padding: 1px 7px; border-radius: 999px; border: 1px solid currentColor; }
.x360-badge--ok { color: var(--nv2-success, #15803d); }
.x360-badge--warn { color: var(--nv2-warning, #b45309); }
.x360-badge--bad { color: var(--nv2-danger, #b91c1c); }
.x360-badge--info { color: var(--nv2-info, #1d4ed8); }
.x360-doors-refused summary { cursor: pointer; font-size: 12px; color: var(--nv2-text-muted, #64748b); }

.x360-held { padding: 10px 12px; border-radius: 10px; border: 1px solid var(--nv2-warning, #b45309);
  background: var(--nv2-warning-bg, #fffbeb); }
.x360-held-line { margin: 0 0 6px; font-size: 13px; font-weight: 600; color: var(--nv2-warning, #b45309); }
.x360-held-list { margin: 0; padding-left: 18px; font-size: 12.5px; }
.x360-held-open { margin-left: 8px; }

.x360-subtabs { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 8px; }
.x360-subtab { border: 1px solid var(--nv2-border, #e2e8f0); background: transparent; cursor: pointer;
  padding: 4px 10px; border-radius: 999px; font-size: 12px; }
.x360-subtab.is-active { background: var(--nv2-surface-alt, #f1f5f9); font-weight: 700; }

.x360-dims { display: flex; flex-wrap: wrap; gap: 8px; }
.x360-dim { display: inline-flex; align-items: center; gap: 6px; padding: 4px 10px; border-radius: 999px;
  border: 1px solid var(--nv2-border, #e2e8f0); background: var(--nv2-surface, #fff); font-size: 12px; }
.x360-dim-label { color: var(--nv2-text-muted, #64748b); }
.x360-dim-value { font-weight: 700; color: var(--x360-tone, inherit); }
.x360-journal { border: 1px solid var(--nv2-border, #e2e8f0); border-radius: 10px; padding: 10px 12px; margin-bottom: 10px; }
.x360-journal-head { display: flex; gap: 12px; flex-wrap: wrap; align-items: baseline; font-size: 13px; font-weight: 600; }
.x360-journal-note { margin: 2px 0 6px; font-size: 12px; color: var(--nv2-text-muted, #64748b); }
.x360-blockers { display: flex; flex-direction: column; gap: 6px; }
.x360-blocker { display: flex; gap: 8px; flex-wrap: wrap; align-items: baseline; font-size: 12.5px;
  padding: 6px 10px; border-radius: 8px; border: 1px solid var(--nv2-danger, #b91c1c); color: var(--nv2-danger, #b91c1c); }
.x360-stack { display: flex; flex-direction: column; gap: 12px; }

/* ═══════════════════════════════════════════════════════════════════════════
   BUREAU DE CHANGE — the .bdc-* block
   (bureau-design/DESIGN-PLAN.md §2, S0–S12; kit branch flow/BDC-design-kit)

   WHY THIS BLOCK EXISTS. The nine bureau routes are the only pages in the
   console that render no nv2-* class at all: rates.jsx was written in Tailwind
   class names this estate never loads (there is no Tailwind in package.json, so
   the Rate Board renders as bare HTML, 5,043px tall for six currencies), and the
   other eight are generic Bootstrap-admin. The cure is to rebuild the pages out
   of ~/components/v2/new — which already owns the card, the table, the form, the
   pill, the stat tile and the empty state. Everything below is the FOUR THINGS
   THAT KIT DOES NOT HAVE, plus the page rhythm that holds them together:

     - the note ladder            (.bdc-ladder / .bdc-rung)
     - the foreign/sterling pair  (.bdc-money-pair / .bdc-rate-chip)
     - the counter status ribbon  (.bdc-ribbon, over nv2-stats-grid-tight)
     - the sheet in the window    (.bdc-sheet, over the printed board's .board-*)

   and four rules the plan states in words: a sentence never lives in a table
   cell (.bdc-row-detail), a regulated sentence gets one shape (.bdc-notice), a
   bureau table must not scroll at 1280 (.bdc-table { min-width: 0 } — the kit's
   .nv2-table carries a 1280px floor for the ledger), and a mode switch that is
   not a door uses .bdc-segmented (deliberately outside the false-doors strip
   regex nav-tabs|nav-pills|nv2-tab-bar|nv2-tabstrip|nv2-cphub-tabs).

   THIS FILE IS MIRRORED. app/components/v2/tokens.css is the source; the browser
   loads public/styles/v2-tokens.css. They must stay byte-identical
   (tests/nv2-tokens-mirror-in-sync.test.js) and root.jsx#NV2_TOKENS_VERSION is
   bumped once per landing.
   ═══════════════════════════════════════════════════════════════════════════ */

/* -- S0. Page root and rhythm --------------------------------------------
   Every bureau route returns <div className="bdc bdc-<page>">. The gap IS the
   rhythm: no p-4, no container-fluid py-3, no mb-4 stacks. */
.bdc { display: flex; flex-direction: column; gap: 20px; }
.bdc h1, .bdc h2, .bdc h3, .bdc h4, .bdc h5, .bdc h6 { margin: 0; }
.bdc p { margin: 0; }
.bdc hr { display: none; }

/* The two outcome presenters (DisplayActionResponse / ActionOutcomeBanner) keep
   their exact pinned JSX and render Bootstrap alerts. They sit between the lede
   and the first card, so they are made to belong rather than replaced. */
.bdc .alert {
  border-radius: var(--nv2-radius);
  border: 1px solid var(--nv2-line);
  box-shadow: var(--nv2-shadow-xs);
  font-size: 13px; line-height: 1.55;
  padding: 12px 14px; margin-bottom: 0;
}
.bdc .alert-danger  { border-left: 4px solid var(--nv2-danger); }
.bdc .alert-warning { border-left: 4px solid var(--nv2-warn); }
.bdc .alert-success { border-left: 4px solid var(--nv2-ok); }
.bdc .alert-info,
.bdc .alert-secondary { border-left: 4px solid var(--nv2-hub-accent, var(--nv2-brand)); }

/* -- S1. The lede bar ----------------------------------------------------
   One 13px sentence capped at 76ch on the left, the page-level actions on the
   right. At phone width the actions wrap under the sentence. */
.bdc-lede { display: flex; align-items: flex-start; justify-content: space-between; gap: 14px 16px; flex-wrap: wrap; }
.bdc-lede-text { flex: 1 1 320px; max-width: 76ch; font-size: 13px; line-height: 1.55; color: var(--nv2-ink-2); }
.bdc-lede-actions { display: flex; align-items: flex-end; gap: 8px; flex-wrap: wrap; margin-left: auto; }
.bdc-standing { flex: 1 1 100%; max-width: 76ch; font-size: 12px; line-height: 1.5; color: var(--nv2-ink-3); }

/* -- S2. Section card ----------------------------------------------------
   Every block of content on every bureau page is one of these. The card's
   explanatory prose is its subtitle — never a floating text-muted paragraph. */
.bdc-section { position: relative; }
.bdc-section-head {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 12px;
  padding: 13px 16px;
  background: var(--nv2-panel-2);
  border-bottom: 1px solid var(--nv2-line-2);
}
.bdc-section-head h3 {
  font-family: var(--nv2-font-display);
  font-size: 14px; font-weight: 700; line-height: 1.3;
  color: var(--nv2-ink);
}
.bdc-section-head p { margin-top: 3px; max-width: 76ch; font-size: 12.5px; line-height: 1.55; color: var(--nv2-ink-2); }
.bdc-section-head-right { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
.bdc-section-body { padding: 16px; display: flex; flex-direction: column; gap: 14px; }
/* A table, a form or a sheet brings its own edges: the body padding would draw a
   second frame inside the card. */
.bdc-section-body.is-flush { padding: 0; gap: 0; }
.bdc-section.is-danger { border-left: 4px solid var(--nv2-danger); }
.bdc-section.is-warn   { border-left: 4px solid var(--nv2-warn); }
.bdc-section.is-info   { border-left: 4px solid var(--nv2-hub-accent, var(--nv2-brand)); }

/* -- S3. Notice — the one shape for a regulated or standing sentence ------
   Words are the service's and are never reworded here; only their typography
   belongs to the designer. */
.bdc-notice {
  font-size: 12.5px; line-height: 1.5;
  color: var(--nv2-ink-2);
  padding: 8px 12px;
  border-left: 3px solid var(--nv2-hub-accent, var(--nv2-brand));
  background: var(--nv2-panel-2);
  border-radius: 0 var(--nv2-radius-sm) var(--nv2-radius-sm) 0;
}
.bdc-notice + .bdc-notice { margin-top: 8px; }
.bdc-notice-label {
  display: block;
  font-size: 10px; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--nv2-ink-3);
  margin-bottom: 3px;
}
.bdc-notice p + p { margin-top: 6px; }
.bdc-notice.is-warn { border-left-color: var(--nv2-warn); background: var(--nv2-warn-soft); color: #78350f; }
.bdc-notice.is-warn .bdc-notice-label { color: #92400e; }
.bdc-notice.is-danger { border-left-color: var(--nv2-danger); background: var(--nv2-danger-soft); color: #7f1d1d; }
.bdc-notice.is-danger .bdc-notice-label { color: #991b1b; }
.bdc-notice.is-ok { border-left-color: var(--nv2-ok); background: var(--nv2-ok-soft); color: #065f46; }
.bdc-notice.is-ok .bdc-notice-label { color: #047857; }

/* -- S4. Data table ------------------------------------------------------
   .nv2-table carries a 1280px floor because the remittance ledger needs one; a
   six-column bureau table must not scroll on a 1280px screen.

   AND THAT SCREEN IS 848px WIDE, NOT 856. The console's content column at a
   1280px browser is 1280 - 72 (rail) - 296 (hub panel) - 28 - 28 (.nv2-content
   padding) = 856, LESS the 8px this sheet gives .nv2-content's scrollbar:
   `.nv2-scope ::-webkit-scrollbar { width: 8px }` at the top of this file, and
   .nv2-content is inside .nv2-scope (shell.jsx nests .nv2-scope > .nv2-app >
   .nv2-main > .nv2-content). 856 - 8 = 848, and a card inside it is 846.

   STYLING ::-webkit-scrollbar IS WHAT MAKES IT TAKE SPACE. Blink answers any
   ::-webkit-scrollbar declaration with a CUSTOM scrollbar, and a custom scrollbar
   is never an overlay - it always occupies layout width. Measured in real desktop
   Chrome on Windows (--headless=new, device scale 1) at a CSS viewport of exactly
   1280: grid track 912px, scrollbar 8px, content box 848px, with an unstyled
   control in the same page reading the platform's own 15px.

   WHY AN EARLIER ROUND READ 856. The lab's headless Chrome reports a 0px
   scrollbar even for a control carrying NO scrollbar styling at all - it
   suppresses scrollbars globally - so it measures 856 and every table looks like
   it fits. Nine routes were signed off that way and the owner still saw a column
   off the right edge. tests/bdc-content-column-848.test.js pins this arithmetic,
   the 8px included, against BOTH sheets. */
.bdc-table { min-width: 0; }
.bdc-table td.is-num, .bdc-table th.is-num { font-variant-numeric: tabular-nums; }
.bdc-table td.is-wrap { white-space: normal; max-width: 28ch; }
.bdc-table td.is-top { vertical-align: top; }
/* A second fact about a cell goes UNDER it. That is how a fifteen-column
   register becomes a ten-column one without losing a fact. */
.bdc-sub {
  display: block; margin-top: 2px;
  font-family: var(--nv2-font-body);
  font-size: 11.5px; font-weight: 500; line-height: 1.4;
  color: var(--nv2-ink-3);
  white-space: normal;
}
.bdc-table td.is-num .bdc-sub { font-weight: 500; }
.bdc-neg { color: #b91c1c; }
.bdc-pos { color: #047857; }
/* A SENTENCE NEVER LIVES IN A CELL. The row that carries sentences gets a detail
   row directly under it, inside the same slice of HTML the row tests read. */
.bdc-row-detail > td {
  padding-top: 0; padding-bottom: 12px;
  background: var(--nv2-panel-2);
  white-space: normal;
}
.bdc-row-detail summary {
  cursor: pointer; list-style: none;
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 11.5px; font-weight: 700; letter-spacing: 0.04em;
  color: var(--nv2-hub-accent, var(--nv2-brand));
  padding: 2px 0;
}
.bdc-row-detail summary::-webkit-details-marker { display: none; }
.bdc-row-detail details > div { margin-top: 8px; }
/* NoDataTable stays where the receipts tests pin it, and reads as the empty card. */
.bdc-table tfoot td, .bdc-table td.bdc-empty-cell {
  padding: 34px 16px;
  text-align: center;
  font-size: 13px; line-height: 1.55;
  color: var(--nv2-ink-3);
  background: var(--nv2-panel-2);
  white-space: normal;
}

/* -- S6. Filters, and the mode switch that is not a door -----------------
   A GET form of labelled fields and one Show button, in the lede's right slot or
   as the first row of the card it filters. */
.bdc-filters { display: flex; align-items: flex-end; gap: 10px; flex-wrap: wrap; }
.bdc-filters .nv2-field { min-width: 150px; }
.bdc-filters .nv2-field-label { font-size: 12px; }
.bdc-section-body > .bdc-filters { padding-bottom: 2px; }
/* .bdc-segmented is a MODE SWITCH, not navigation: it changes which form the one
   card shows and never the URL, so it is deliberately outside the false-doors
   strip regex and needs no page-tab-strips.js entry. */
.bdc-segmented { display: inline-flex; flex-wrap: wrap; gap: 4px; padding: 4px; background: var(--nv2-bg-2); border-radius: 999px; }
.bdc-segmented button {
  border: 0; background: transparent; cursor: pointer;
  padding: 6px 14px; border-radius: 999px;
  font-family: inherit; font-size: 12.5px; font-weight: 600;
  color: var(--nv2-ink-2);
  transition: all 120ms ease;
}
.bdc-segmented button:hover { color: var(--nv2-ink); }
.bdc-segmented button.is-active {
  background: white; color: var(--nv2-hub-accent, var(--nv2-brand));
  box-shadow: var(--nv2-shadow-xs);
}

/* -- S8. Forms -----------------------------------------------------------
   One layout: FormCard > Fieldset > FieldRow > Field > input > FormFooter. */
.bdc-form-narrow { max-width: 720px; }
.bdc .nv2-form-footer { flex-wrap: wrap; gap: 10px; }
.bdc .nv2-form-footer > :first-child { max-width: 66ch; font-size: 12px; line-height: 1.5; color: var(--nv2-ink-2); }
/* A destructive press is an outline until the confirm step, where it fills. */
.bdc-btn-danger-solid {
  background: var(--nv2-danger); border-color: var(--nv2-danger); color: white;
}
.bdc-btn-danger-solid:hover { background: #dc2626; border-color: #dc2626; color: white; }
/* A per-row editor (the counter register, Receive an order) is a disclosure, so
   the form stays in the markup — closed — for the readers that assert on it. */
.bdc-disclosure > summary {
  cursor: pointer; list-style: none;
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px; font-weight: 700;
  color: var(--nv2-hub-accent, var(--nv2-brand));
}
.bdc-disclosure > summary::-webkit-details-marker { display: none; }
.bdc-disclosure[open] > summary { margin-bottom: 10px; }
/* The chosen customer: the read-only name the teller reads, with Clear beside it. */
.bdc-picker { display: flex; align-items: stretch; gap: 8px; }
.bdc-picker .nv2-field-input { flex: 1 1 auto; min-width: 0; }
/* Find a customer: one labelled box that takes the room the row has, then its press. */
.bdc-find .nv2-field { flex: 1 1 260px; max-width: 480px; }
/* A confirmation the ROUTE writes itself (bdc-fix-r4-till reads its name out of
   the route's own source), placed by the kit: the box, then the sentence. */
.bdc-check { display: flex; align-items: flex-start; gap: 8px; font-size: 12.5px; font-weight: 500; line-height: 1.45; color: var(--nv2-ink-2); cursor: pointer; }
.bdc-check input { margin-top: 2px; flex-shrink: 0; }

/* -- S10a. The note ladder -----------------------------------------------
   The rungs are the currency's own (bureau-note-ladder), so the tiles wrap and
   the count is the only thing the teller types. */
.bdc-ladder { display: flex; flex-direction: column; gap: 10px; }
.bdc-ladder-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(124px, 1fr)); gap: 10px; }
.bdc-rung {
  display: flex; flex-direction: column; gap: 5px;
  padding: 10px 12px;
  border: 1px solid var(--nv2-line);
  border-radius: var(--nv2-radius-sm);
  background: var(--nv2-panel);
}
.bdc-rung-face { font-family: var(--nv2-font-display); font-size: 18px; font-weight: 700; line-height: 1; color: var(--nv2-ink); }
.bdc-rung input { width: 100%; }
.bdc-ladder-total {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
  padding: 9px 12px;
  border-radius: var(--nv2-radius-sm);
  background: var(--nv2-bg-2);
  font-size: 12.5px; color: var(--nv2-ink-2);
}
.bdc-ladder-empty { font-size: 12.5px; color: var(--nv2-ink-3); }

/* -- S10b. The foreign / sterling pair -----------------------------------
   Two money boxes with the rate stated between them, so what the customer hands
   over and what they get back are read as one act. */
.bdc-money-pair { display: grid; grid-template-columns: 1fr auto 1fr; align-items: start; gap: 12px; }
.bdc-rate-chip {
  align-self: center; margin-top: 18px;
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 12px; border-radius: 999px;
  border: 1px solid var(--nv2-line);
  background: var(--nv2-panel-2);
  font-family: var(--nv2-font-mono);
  font-size: 12px; font-weight: 700; white-space: nowrap;
  color: var(--nv2-ink-2);
}

/* -- S10c. The counter status ribbon -------------------------------------
   Facts the loader already gives — never a computed money figure. */
.bdc-ribbon .nv2-stat-card { cursor: default; }
.bdc-ribbon .bdc-notice { margin-top: 8px; }

/* Definition strips: the customer's facts, the vault's paying-in list. */
.bdc-facts { display: flex; flex-wrap: wrap; gap: 10px 28px; }
.bdc-fact-label { display: block; font-size: 10.5px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--nv2-ink-3); }
.bdc-fact-value { font-size: 13px; font-weight: 600; color: var(--nv2-ink); }
.bdc-dl { display: flex; flex-direction: column; gap: 8px; }
.bdc-dl-row { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; padding-bottom: 8px; border-bottom: 1px solid var(--nv2-line-2); }
.bdc-dl-row:last-child { border-bottom: 0; padding-bottom: 0; }
.bdc-dl-row .is-id { font-family: var(--nv2-font-display); font-weight: 700; }
.bdc-dl-row .is-num { font-variant-numeric: tabular-nums; font-weight: 700; }
.bdc-two-up { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; align-items: start; }

/* -- S10d. The sheet in the window ---------------------------------------
   The Rate Board's "What customers will see" renders the PRINTED BOARD's own
   markup at two thirds, so the preview and the paper cannot drift: the .board-*
   rules below are the printer route's, moved here for both to share. */
.bdc-sheet { background: var(--nv2-bg-2); padding: 16px; display: flex; justify-content: center; }
.bdc-sheet .board-page {
  width: 100%; max-width: 640px; min-height: 0;
  margin: 0; padding: 18px 20px;
  box-shadow: var(--nv2-shadow-sm);
  border-radius: var(--nv2-radius-sm);
}
.bdc-sheet h1.board-title { font-size: 23px; }
.bdc-sheet .board-subtitle { font-size: 11px; }
.bdc-sheet table.board-tbl td.ccy { font-size: 14px; }
.bdc-sheet table.board-tbl td.num { font-size: 15px; }
.bdc-sheet table.board-tbl td { padding: 6px 7px; }
.bdc-sheet .board-empty { padding: 20px 16px; }
.bdc-sheet .board-empty p { font-size: 12.5px; }
.bdc-sheet .board-masthead .brand img { height: 22px; }

/* -- S12. Responsive — the page is one column at phone width --------------
   The shell collapses its rail at 900px. */
@media (max-width: 991px) {
  .bdc-two-up { grid-template-columns: 1fr; }
}
@media (max-width: 720px) {
  .bdc-money-pair { grid-template-columns: 1fr; }
  .bdc-rate-chip { margin-top: 0; justify-self: start; }
}
@media (max-width: 640px) {
  .bdc { gap: 16px; }
  .bdc .nv2-field-row, .bdc .nv2-field-row.is-thirds { grid-template-columns: 1fr; }
  .bdc-lede-actions { margin-left: 0; width: 100%; }
  .bdc-filters .nv2-field { min-width: 0; flex: 1 1 140px; }
  .bdc-ladder-grid { grid-template-columns: 1fr 1fr; }
  .bdc-section-head { flex-direction: column; }
  .bdc-facts { gap: 10px 18px; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   THE PRINTED RATE BOARD — .board-page / .board-* (design plan §3.10, S10)

   These rules were the /printer/bureau-rate-board route's own <style> block
   (flow/N3709-printboard). They live here so the printed sheet and the Rate
   Board's preview of it are ONE typesetting: a sheet that goes in a window and
   a preview that claims to show it must not be two stylesheets that drift.

   THE PAGE IS .board-page AND THE STRIP IS .board-toolbar — NOT .print-page /
   .print-toolbar, which is what the route's inline copy called them. Two other
   printer routes that are not the board, printer/bureau-receipt.$id and
   printer/office-receipt.$id, render .print-page and .print-toolbar with inline
   sheets of their own, and this file is loaded by EVERY console page: a rule
   here for .print-page would put both receipts in a flex column (no margin
   collapse, every text run a flex item) and hand them the phone-width override
   below. So the board's page has a name of its own, the served sheet carries
   no .print-page or .print-toolbar rule at all (tests/bdc-design-kit.test.js,
   K8b), and when the printed-board branch lands on this kit its route renders
   <div className="board-toolbar"> and <div className="board-page">. Every other
   class name is unchanged, so npn-3709-printed-rate-board.test.js keeps its
   bordered / padded / background claims, read from this sheet instead of the
   route's inline copy.

   WHAT DELIBERATELY DID NOT MOVE: the route's global rules (the universal
   box-sizing reset, html and body, the page-size at-rule and the bare tr / thead
   print rules) and the toolbar's own button styling (the plan makes Print and
   Close two nv2-btns). A sheet every console page loads may not restyle the
   document or repaginate every other page's tables, so the route keeps those
   lines, and the print-media rules below are scoped under .board-page.
   ═══════════════════════════════════════════════════════════════════════════ */
.board-toolbar { width: 210mm; max-width: 100%; margin: 16px auto 8px auto; display: flex; justify-content: flex-end; gap: 8px; }
.board-page { width: 210mm; min-height: 297mm; padding: 14mm; margin: 0 auto 24px auto; background: #fff;
  box-shadow: 0 2px 8px rgba(0,0,0,0.12); display: flex; flex-direction: column; }

/* -- masthead ------------------------------------------------------------ */
.board-masthead { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px;
  padding-bottom: 9px; border-bottom: 2px solid #1d4ed8; }
.board-masthead .brand img { height: 32px; width: auto; display: block; }
.board-masthead .doc-type { text-align: right; font-size: 10.5px; color: #4b5563; line-height: 1.5; }
.board-masthead .doc-type .label { font-family: var(--nv2-font-display); font-size: 11.5px; font-weight: 700; color: #1d4ed8;
  letter-spacing: 1.4px; text-transform: uppercase; }

/* -- title --------------------------------------------------------------- */
.board-head { margin: 15px 0 12px 0; }
h1.board-title { font-size: 34px; line-height: 1.08; margin: 0; letter-spacing: -0.4px; font-weight: 700; }
.board-subtitle { margin-top: 6px; font-size: 12.5px; color: #4b5563; letter-spacing: 0.2px; }

/* -- the rates ----------------------------------------------------------- */
table.board-tbl { width: 100%; border-collapse: collapse; }
table.board-tbl th { font-size: 10px; text-transform: uppercase; letter-spacing: 1.4px; color: #374151;
  text-align: left; padding: 0 10px 6px 10px; border-bottom: 2px solid #111827; font-weight: 700; }
table.board-tbl th.num { text-align: right; }
table.board-tbl td { padding: 9px 10px; border-bottom: 1px solid #e5e7eb; vertical-align: middle; }
table.board-tbl tbody tr:nth-child(even) td { background: #f8fafc; }
table.board-tbl td.ccy { font-size: 19px; font-weight: 700; letter-spacing: 1px; }
table.board-tbl td.num { text-align: right; font-size: 21px; font-weight: 600; font-variant-numeric: tabular-nums; }
table.board-tbl td.when { font-size: 10.5px; color: #4b5563; line-height: 1.4; }
table.board-tbl td.when .by { color: #6b7280; }

/* -- the empty state, and the refusal ------------------------------------ */
.board-empty { margin: 16px 0 6px 0; border: 2px dashed #cbd5e1; border-radius: 6px; background: #f8fafc;
  padding: 26px 22px; text-align: center; }
.board-empty .board-state-label { display: inline-block; font-size: 10px; font-weight: 700; letter-spacing: 1.6px;
  text-transform: uppercase; color: #92400e; background: #fef3c7; border: 1px solid #fcd34d;
  border-radius: 999px; padding: 3px 11px; }
.board-empty p { margin: 11px auto 0 auto; max-width: 125mm; font-size: 14px; line-height: 1.55; color: #374151; }
.board-refusal { margin: 16px 0 6px 0; border: 1px solid #fca5a5; border-left: 6px solid #b91c1c;
  border-radius: 6px; background: #fef2f2; padding: 20px 22px; }
.board-refusal .board-state-label { display: inline-block; font-size: 10px; font-weight: 700; letter-spacing: 1.6px;
  text-transform: uppercase; color: #b91c1c; }
.board-refusal p { margin: 9px 0 0 0; font-size: 14px; line-height: 1.55; color: #7f1d1d; }

/* -- the conditions ------------------------------------------------------ */
.board-conditions { margin-top: 12px; flex: 1; display: flex; flex-direction: column; }
.board-note { font-size: 11.5px; color: #374151; line-height: 1.5; border-left: 3px solid #1d4ed8;
  padding: 3px 0 3px 10px; margin-bottom: 14px; }
.board-note .board-note-label { display: block; font-size: 9.5px; font-weight: 700; letter-spacing: 1.2px;
  text-transform: uppercase; color: #6b7280; margin-bottom: 2px; }
.board-note p { margin: 0; }
.board-sec-head { font-size: 10px; font-weight: 700; letter-spacing: 1.6px; text-transform: uppercase;
  color: #6b7280; border-top: 1px solid #d1d5db; padding-top: 7px; margin-bottom: 9px; }
.board-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px 14px; align-items: start; }
.board-card { border: 1px solid #d1d5db; border-radius: 5px; padding: 9px 12px;
  break-inside: avoid; page-break-inside: avoid; }
.board-card-wide { grid-column: 1 / -1; }
.board-card h2 { margin: 0 0 5px 0; font-size: 10.5px; font-weight: 700; letter-spacing: 1px;
  text-transform: uppercase; color: #1d4ed8; }
.board-card p.board-card-line { margin: 0; font-size: 11.5px; line-height: 1.45; color: #1f2937; }
.board-card ul { margin: 0; padding-left: 15px; }
.board-card li { font-size: 11.5px; line-height: 1.45; color: #1f2937; margin-bottom: 3px; }
.board-card li:last-child { margin-bottom: 0; }
.board-complaints { margin-top: auto; border: 1px solid #111827; border-radius: 5px; background: #f9fafb;
  padding: 10px 13px; break-inside: avoid; page-break-inside: avoid; }
.board-complaints h2 { margin: 0 0 5px 0; font-size: 10.5px; font-weight: 700; letter-spacing: 1px;
  text-transform: uppercase; color: #111827; }
.board-complaints p { margin: 0 0 4px 0; font-size: 11.5px; line-height: 1.5; color: #1f2937; }
.board-complaints p:last-child { margin-bottom: 0; }

/* -- the sheet on a phone (plan 3.10): a 794px canvas in a 400px viewport is a
   sideways scroll, so the fixed A4 width is dropped on screen. Print is
   unaffected — the @media print block below restores block flow for paper. -- */
@media (max-width: 720px) {
  .board-toolbar { width: auto; margin: 12px 16px 8px; }
  .board-page { width: auto; min-height: 0; padding: 16px; margin: 0 8px 16px; }
  .board-grid { grid-template-columns: 1fr; }
  h1.board-title { font-size: 26px; }
}

@media print {
  .board-toolbar { display: none; }
  /* A flex container paginates badly: the sheet goes back to block flow for
     print, and the foot band simply follows the conditions. */
  .board-page { width: auto; min-height: 0; padding: 0; margin: 0; box-shadow: none; display: block; }
  .board-conditions { display: block; }
  .board-complaints { margin-top: 12px; }
  h1.board-title { font-size: 30px; }
  .board-page tr { page-break-inside: avoid; break-inside: avoid; }
  .board-page thead { display: table-header-group; }
  .board-empty, .board-refusal, .board-note, .board-card, .board-complaints {
    page-break-inside: avoid; break-inside: avoid; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   BUREAU REPORTS — what the report cards add to the .bdc-* block
   (bureau-design/DESIGN-PLAN.md §3.2; builder D, flow/BD-reports)

   Five reports, one card each: the section head, the window the report covers
   as the card's first row, the rule for that window, then the register. The
   kit's BdcSection is used `flush` because a table brings its own edges, so the
   rows that are not the table (the filter strip, a notice, the empty card) get
   their gutters here. Every selector is keyed to a bureau class, so nothing
   outside /bureau changes.
   ═══════════════════════════════════════════════════════════════════════════ */

/* The window a report covers: a muted strip across the top of its card. */
.bdc-section-body.is-flush > .bdc-filters {
  padding: 12px 16px;
  background: var(--nv2-panel-2);
  border-bottom: 1px solid var(--nv2-line-2);
}
/* A notice in a flush card keeps the card's gutter. */
.bdc-section-body.is-flush > .bdc-notice { margin: 12px 16px 0; }
.bdc-section-body.is-flush > .bdc-notice + .bdc-notice { margin-top: 8px; }
.bdc-section-body.is-flush > .bdc-notice:last-child { margin-bottom: 16px; }
.bdc-section-body.is-flush > .bdc-notice + .nv2-table-toolbar,
.bdc-section-body.is-flush > .bdc-notice + .nv2-table-scroll { margin-top: 12px; border-top: 1px solid var(--nv2-line-2); }
/* An empty window is the kit's dashed card, inside the frame of the card it empties. */
.bdc-section-body.is-flush > .nv2-empty-card { margin: 16px; padding: 40px 24px; }
.bdc .nv2-empty-card .nv2-empty-icon { color: var(--nv2-ink-3); line-height: 1; }
.bdc .nv2-empty-card h3 { font-family: var(--nv2-font-display); }
/* The bureau's own `.bdc p { margin: 0 }` reset sits LATER in this sheet than
   `.nv2-empty-card p { margin: 0 auto }` and carries the same specificity, so it won
   and every bureau empty state printed its sentence flush left under a centred title.
   Measured on the Reports daily-empty capture: card 45-755, the sentence at x=70. */
.bdc .nv2-empty-card p { margin: 0 auto; }

/* A press in a card head, with the sentence that says why it cannot act under it. */
.bdc-head-stack { display: flex; flex-direction: column; align-items: flex-end; gap: 6px; max-width: 34ch; text-align: right; }
/* The sentence under a dead press is the REASON the door is shut, not a footnote to a
   figure: it takes the prose ink like every other explanation on the page. .bdc-sub keeps
   the hint ink everywhere else, where it carries a second fact under a number. */
.bdc-head-stack .bdc-sub { margin-top: 0; font-size: 12px; color: var(--nv2-ink-2); }

/* The ribbon keeps the page's own rhythm: the v2 strip carries a 22px bottom margin
   for the ledger's layout, and under .bdc the 20px page gap is the spacing. */
.bdc .bdc-ribbon .nv2-stats-grid { margin-bottom: 0; }

/* Report tables. The heads are phrases a person reads ("Notes at today's market
   rate"), so they wrap rather than push the tenth column off a 1280 screen. */
.bdc-reports .bdc-table thead th { white-space: normal; vertical-align: bottom; line-height: 1.3; }
.bdc-reports .bdc-table td.is-wrap { min-width: 26ch; max-width: 48ch; line-height: 1.45; }
.bdc-reports .nv2-table-toolbar { flex-wrap: wrap; gap: 6px 16px; }
.bdc-reports .is-warn-text { color: #92400e; font-weight: 600; }
.bdc-table td.is-mono { font-family: var(--nv2-font-mono); font-size: 12px; }
.bdc-table td.is-muted,
.bdc-table td.is-num.is-muted { color: var(--nv2-ink-3); font-weight: 500; }
.bdc-table td.is-id a { color: inherit; text-decoration: none; border-bottom: 1px solid var(--nv2-line); }
.bdc-table td.is-id a:hover { color: var(--nv2-hub-accent, var(--nv2-brand)); border-bottom-color: currentColor; }
/* A group's name is said once, down the rows it covers. */
.bdc-table tr.bdc-group-start > td { border-top: 1px solid var(--nv2-line); }

/* A report's total is a footer row of its own. The kit styles a bare <tfoot> cell
   as the empty card (NoDataTable renders there), so the total row names itself
   and outranks that rule. */
.bdc-table tfoot tr.bdc-total > th,
.bdc-table tfoot tr.bdc-total > td {
  padding: 12px 16px;
  text-align: left; white-space: nowrap;
  font-family: var(--nv2-font-display); font-size: 13px; font-weight: 700; line-height: 1.4;
  color: var(--nv2-ink);
  background: var(--nv2-panel-2);
  border-top: 1px solid var(--nv2-line);
}
.bdc-table tfoot tr.bdc-total > td.is-num { text-align: right; font-family: var(--nv2-font-mono); font-variant-numeric: tabular-nums; }
.bdc-table tfoot tr.bdc-total > td.is-muted { color: var(--nv2-ink-3); font-weight: 500; }
.bdc-table tfoot tr.bdc-total .bdc-sub { font-weight: 500; }

/* A register wider than the card (the HMRC record) keeps its identity column in
   view while it scrolls sideways. */
.bdc-table.bdc-sticky-id thead th:first-child,
.bdc-table.bdc-sticky-id tbody td:first-child { position: sticky; left: 0; z-index: 1; box-shadow: 1px 0 0 var(--nv2-line-2); }
.bdc-table.bdc-sticky-id tbody td:first-child { background: white; }
.bdc-table.bdc-sticky-id tbody tr:hover td:first-child { background: var(--nv2-panel-2); }

@media (max-width: 640px) {
  .bdc-section-body.is-flush > .bdc-filters { padding: 12px; }
  .bdc-section-body.is-flush > .bdc-notice { margin-left: 12px; margin-right: 12px; }
  .bdc-section-body.is-flush > .nv2-empty-card { margin: 12px; padding: 28px 16px; }
  .bdc-head-stack { align-items: flex-start; text-align: left; max-width: none; }
  .bdc-reports .bdc-table thead th,
  .bdc-reports .bdc-table tbody td,
  .bdc-reports .bdc-table tfoot tr.bdc-total > th,
  .bdc-reports .bdc-table tfoot tr.bdc-total > td { padding-left: 10px; padding-right: 10px; }
  .bdc-reports .bdc-table td.is-id { white-space: normal; }
  .bdc-reports .nv2-table-toolbar,
  .bdc-reports .nv2-table-footer { padding-left: 12px; padding-right: 12px; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   BUREAU DE CHANGE — THE RATE BOARD'S OWN FEW RULES (/bureau/rates)
   (bureau-design/DESIGN-PLAN.md §3.1; flow/BD-rates, on top of the kit's block)

   Everything else on the page is the kit's (.bdc-*) and the v2 kit's (.nv2-*).
   These are only what this one page needs and the kit does not draw: the four
   publish steps as one card with a rule between them and an amber step when the
   door would require a reason; a notice that sits inside a flush card; the
   blockers list in the press's footer; the register's per-currency editor row; and
   a detail row that stays readable inside a table that scrolls sideways on a
   phone. Every rule is scoped under .bdc-rates so no other bureau page inherits it.
   ═══════════════════════════════════════════════════════════════════════════ */
.bdc-rates .bdc-section-body.is-flush > .bdc-inset { margin: 12px 16px; }
.bdc-rates .bdc-section-body.is-flush > .bdc-inset + .bdc-inset { margin-top: 0; }

/* The four steps of one publication: one card, a rule between steps, and the step
   the door would stop on drawn amber before the press rather than after it. */
.bdc-rates .bdc-step { border-bottom: 1px solid var(--nv2-line-2); }
.bdc-rates .bdc-step > .nv2-fieldset { border-bottom: 0; }
.bdc-rates .bdc-step.is-required { background: var(--nv2-warn-soft); box-shadow: inset 4px 0 0 var(--nv2-warn); }
.bdc-rates .bdc-step .bdc-notice { margin-bottom: 12px; }
.bdc-rates .bdc-step .bdc-check { margin: 2px 0 12px; }
.bdc-rates .bdc-step-sub { margin: -6px 0 12px; max-width: 76ch; font-size: 12px; line-height: 1.5; color: var(--nv2-ink-3); }
.bdc-rates .bdc-step .nv2-field-input:disabled { background: var(--nv2-bg-2); color: var(--nv2-ink-3); cursor: not-allowed; }
.bdc-rates .bdc-step-press .nv2-form-footer { border-top: 0; }
.bdc-rates .bdc-blockers { margin: 6px 0 0; padding-left: 18px; }
.bdc-rates .bdc-blockers li + li { margin-top: 4px; }

/* The summary beside the form stays in view while the steps scroll past it. */
.bdc-rates .bdc-rates-publish .nv2-side-panel { top: 16px; }

/* The register: one editor row under each currency, opened in place. */
.bdc-rates .bdc-row-editor .nv2-field-row { margin-bottom: 10px; }
.bdc-rates .bdc-row-editor-foot {
  display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap;
  font-size: 12px; line-height: 1.5; color: var(--nv2-ink-2);
}

@media (max-width: 640px) {
  /* A seven-column board scrolls sideways at phone width; the sentences under a row
     stay on the screen instead of running the width of the table. */
  .bdc-rates .bdc-row-detail details { position: sticky; left: 12px; max-width: calc(100vw - 72px); }
}

/* The printed sheet on a phone (bureau-design §3.10). The sheet gives up its fixed A4
   width under 720px — the kit's rule — but the rate table's own minimum still did not
   fit: two 21px figures and an unbreakable publisher e-mail in "Valid from" made a 491px
   canvas in a 400px viewport (measured). The figures step down, the cells tighten and the
   publisher line is allowed to break, so the sheet fits the screen a teller checks it on.
   The paper is unaffected: an A4 page is 794px wide, so this query never matches it. */
@media (max-width: 720px) {
  table.board-tbl th, table.board-tbl td { padding: 6px 6px; }
  table.board-tbl td.ccy { font-size: 16px; }
  table.board-tbl td.num { font-size: 16px; }
  table.board-tbl td.when { font-size: 9.5px; overflow-wrap: anywhere; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   BUREAU DE CHANGE — the counter pages: Sell, Buy, Bureau Till, Day End
   (bureau-design/DESIGN-PLAN.md §3.3–§3.6; flow/BD-counter, built on the kit above)

   The kit above owns every shared piece. This block holds only what the four
   counter pages lay out around those pieces and nothing any other bureau page
   reads: the sticky quote column beside the exchange form, the walk-in
   disclosure as a card inside "Find a customer", the till's mode bar, the dense
   ten-column positions table, the inline decision form, and the counter status
   ribbon's own widths (its tiles carry a pill or a name, not a 22px figure, and
   its definitions are sentences, so they wrap instead of scrolling). Every rule
   is scoped to a class these pages set, so no other page moves.
   tests/bdc-counter-design.test.js holds each class a counter page renders to a
   rule in the served sheet.
   ═══════════════════════════════════════════════════════════════════════════ */

/* The rhythm inside the form grid, and the right column that stays beside the form. */
.bdc [hidden] { display: none !important; }
.bdc-stack { display: flex; flex-direction: column; gap: 20px; min-width: 0; }
.bdc-form-stack { display: flex; flex-direction: column; gap: 12px; }
.bdc-side { display: flex; flex-direction: column; gap: 20px; min-width: 0; position: sticky; top: 16px; }
.bdc-side .nv2-side-panel { position: static; }
.bdc-side .nv2-calc-value { font-variant-numeric: tabular-nums; text-align: right; }
.bdc-side .nv2-side-panel-body > .bdc-sub { margin-top: 10px; line-height: 1.5; }
.bdc-side .nv2-side-panel-body > .nv2-btn { margin-top: 12px; width: 100%; justify-content: center; }

/* Small words and presses. */
.bdc-muted { color: var(--nv2-ink-3); font-weight: 400; }
.bdc-btn-sm { padding: 5px 10px; font-size: 12px; }
.bdc-btn-link { border-color: transparent; background: transparent; color: var(--nv2-ink-2); }
.bdc-btn-link:hover { border-color: transparent; }
.bdc-actions-row { display: flex; align-items: center; justify-content: flex-end; gap: 8px; flex-wrap: wrap; }
.bdc-check-help { display: block; margin-top: 2px; font-size: 11.5px; font-weight: 500; color: var(--nv2-danger); }
.bdc-fieldset-lede { max-width: 76ch; margin: 0 0 14px; font-size: 12.5px; line-height: 1.55; color: var(--nv2-ink-2); }
.bdc-dl-empty { font-size: 12.5px; color: var(--nv2-ink-3); }

/* The exchange: the two money boxes read as figures, and a rung that holds notes is marked. */
.bdc-money-pair .nv2-field-input { font-family: var(--nv2-font-mono); font-size: 15px; font-weight: 700; text-align: right; }
.bdc-rung input { font-family: var(--nv2-font-mono); font-weight: 700; text-align: right; }
.bdc-rung.is-picked { border-color: var(--nv2-hub-accent, var(--nv2-brand)); box-shadow: inset 0 0 0 1px var(--nv2-hub-accent, var(--nv2-brand)); }

/* "Find a customer": the walk-in add is a card that opens inside the card. */
.bdc-counter-find .bdc-disclosure { border: 1px solid var(--nv2-line); border-radius: var(--nv2-radius-sm); background: var(--nv2-panel); overflow: hidden; }
.bdc-counter-find .bdc-disclosure > summary { display: flex; padding: 10px 14px; font-size: 12.5px; }
.bdc-counter-find .bdc-disclosure > summary::after { content: "+"; margin-left: auto; font-weight: 700; color: var(--nv2-ink-3); }
.bdc-counter-find .bdc-disclosure[open] > summary { margin-bottom: 0; border-bottom: 1px solid var(--nv2-line-2); }
.bdc-counter-find .bdc-disclosure[open] > summary::after { content: "\2212"; }
.bdc-counter-find .bdc-disclosure > form { padding: 14px 14px 0; }
.bdc-counter-find .bdc-disclosure > form > .nv2-form-footer { margin: 2px -14px 0; padding: 12px 14px; }
.bdc-counter-find .bdc-disclosure > button { margin: 12px 14px; }

/* Bureau Till: the mode bar over the one form it shows, the dense positions table, the inline decision. */
.bdc-mode-bar { padding: 14px 22px 0; }
.bdc-table.is-dense thead th { padding-left: 10px; padding-right: 10px; }
.bdc-table.is-dense tbody td { padding-left: 10px; padding-right: 10px; font-size: 12.5px; }
.bdc-inline-form { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.bdc-inline-form .nv2-field-input { width: 200px; padding: 6px 10px; font-size: 12.5px; }

/* The counter status ribbon: a name or a pill in each tile, and definitions that wrap. */
.bdc-ribbon.is-counter .nv2-stats-grid { margin-bottom: 0; }
.bdc-ribbon.is-counter .nv2-stat-card.has-side-icon .nv2-stat-value {
  font-size: 16px; white-space: normal; line-height: 1.25;
  display: flex; align-items: center; flex-wrap: wrap; gap: 6px;
}
.bdc-ribbon.is-counter .nv2-stat-def { white-space: normal; }
@media (max-width: 1280px) {
  .bdc-ribbon.is-counter .nv2-stats-grid-tight .nv2-stat-card { border-top: 0; }
}
@media (max-width: 991px) {
  .bdc-side { position: static; }
}
@media (max-width: 900px) {
  .bdc-ribbon.is-counter .nv2-stats-grid-tight.nv2-stats-grid-5 { grid-template-columns: repeat(2, minmax(0, 1fr)); overflow-x: visible; }
  .bdc-ribbon.is-counter .nv2-stats-grid-tight.nv2-stats-grid-5 .nv2-stat-card { min-width: 0; border-left: 0; border-top: 1px solid var(--nv2-line); }
  .bdc-ribbon.is-counter .nv2-stats-grid-tight.nv2-stats-grid-5 .nv2-stat-card:nth-child(-n+2) { border-top: 0; }
  .bdc-ribbon.is-counter .nv2-stats-grid-tight.nv2-stats-grid-5 .nv2-stat-card:nth-child(even) { border-left: 1px solid var(--nv2-line); }
}
@media (max-width: 640px) {
  .bdc-mode-bar { padding: 12px 16px 0; }
  .bdc-inline-form .nv2-field-input { width: 100%; }
}
@media (max-width: 540px) {
  .bdc-ribbon.is-counter .nv2-stats-grid-tight.nv2-stats-grid-3,
  .bdc-ribbon.is-counter .nv2-stats-grid-tight.nv2-stats-grid-5 { grid-template-columns: 1fr; }
  .bdc-ribbon.is-counter .nv2-stats-grid-tight .nv2-stat-card { border-left: 0; }
  .bdc-ribbon.is-counter .nv2-stats-grid-tight .nv2-stat-card + .nv2-stat-card { border-top: 1px solid var(--nv2-line); }
  .bdc-ribbon.is-counter .nv2-stats-grid-tight.nv2-stats-grid-5 .nv2-stat-card:nth-child(even) { border-left: 0; }
  .bdc-ribbon.is-counter .nv2-stats-grid-tight.nv2-stats-grid-5 .nv2-stat-card:nth-child(2) { border-top: 1px solid var(--nv2-line); }
  .bdc-ribbon.is-counter .nv2-stats-grid-tight .nv2-stat-card.has-side-icon .nv2-stat-body { min-width: 0; }
}

/* The Bureau Till's ten-column register fits a 1280 screen, and the state it ends
   with is never cut off: the money cells keep their currency code (S9), so the
   columns give the room back in padding and the state cell wraps instead of
   scrolling the card. Measured on the rendered page: the status pill for a
   difference waiting for a second person was clipped at the card's right edge. */
.bdc-till .bdc-table.is-dense th, .bdc-till .bdc-table.is-dense td { padding-left: 8px; padding-right: 8px; }
.bdc-till .bdc-table.is-dense th:last-child, .bdc-till .bdc-table.is-dense td:last-child { white-space: normal; }
.bdc-till .bdc-table.is-dense td:last-child .nv2-pill { white-space: normal; flex-wrap: wrap; row-gap: 0; }
/* A confirmation that is a fieldset's own row (Buy's authenticity check) needs the
   same air as a field would have; the kit's .bdc-check is a placement, not a row. */
.bdc .nv2-fieldset > .bdc-check { margin-top: 10px; }

/* ═══════════════════════════════════════════════════════════════════════════
   BUREAU REGISTERS — the addendum for Stock, Receipts, Counter Customers and the
   /bureau layout (bureau-design/DESIGN-PLAN.md §3.7–§3.9; flow/BD-registers)

   Everything shared is the kit's block above and is not restated here. This is
   only what those three registers draw that the kit does not: the filter row and
   a padded block inside a flush card, a form card or an empty card lying flat
   inside one, a card nested in a card (the customer's own sub-sections), the row
   presses, the per-row disclosure (Receive an order), the reason a row cannot be
   voided, the person head, the walk-in form drawn as a card, the one modal the
   bureau keeps (Void a receipt), a form card that carries a tone rule of its own,
   and the refusal card the layout draws. Every rule is scoped to a .bdc root or to
   a bdc-* class of its own, so no other console page is restyled.
   ═══════════════════════════════════════════════════════════════════════════ */
.bdc > .nv2-tab-bar { margin-bottom: 0; }

/* Inside a flush card: the filter row first, padded blocks, flat children. */
.bdc-toolbar { padding: 12px 16px; background: var(--nv2-panel-2); border-bottom: 1px solid var(--nv2-line-2); }
.bdc-pad { padding: 14px 16px; display: flex; flex-direction: column; gap: 12px; }
.bdc-section-body.is-flush > .nv2-form-card { border: 0; border-top: 1px solid var(--nv2-line-2); border-radius: 0; box-shadow: none; }
.bdc-section-body.is-flush > .nv2-form-card:first-child { border-top: 0; }
.bdc-section-body.is-flush > .nv2-empty-card { margin: 16px; padding: 28px 20px; border-radius: var(--nv2-radius-sm); background: var(--nv2-panel-2); }
.bdc .nv2-empty-card .nv2-empty-icon { font-size: 30px; margin-bottom: 8px; }
.bdc .nv2-empty-card h3 { font-family: var(--nv2-font-display); }
.bdc .nv2-empty-card p { max-width: 60ch; }

/* A card inside a card — the customer's linked exchanges and transfers. */
.bdc-section.bdc-subsection { border: 0; border-top: 1px solid var(--nv2-line-2); border-radius: 0; box-shadow: none; }
.bdc-subsection > .bdc-section-head { background: var(--nv2-panel); border-bottom: 0; padding-bottom: 2px; }

/* A form card that carries a tone rule of its own (Quarantine a note, Report a concern). */
.bdc .nv2-form-card.bdc-tone-danger { border-left: 4px solid var(--nv2-danger); }
.bdc .nv2-form-card.bdc-tone-warn { border-left: 4px solid var(--nv2-warn); }

/* The row presses: right-aligned, 12px, a form inside them invisible to the layout. */
.bdc-table th.is-actions, .bdc-table td.is-actions { text-align: right; }
.bdc-row-actions { display: flex; gap: 6px; justify-content: flex-end; align-items: center; flex-wrap: wrap; }
.bdc-row-actions form { display: contents; }
.bdc-row-actions .nv2-btn { padding: 5px 10px; font-size: 12px; }
.bdc-table td.is-wrap.is-wide { max-width: 48ch; }
.bdc-cell-stack { display: flex; flex-direction: column; align-items: flex-start; gap: 3px; margin-top: 4px; }
.bdc-mono { font-family: var(--nv2-font-mono); }
.bdc-table td.bdc-mono { font-size: 12px; }
.bdc-quiet { font-size: 12.5px; color: var(--nv2-ink-3); }

/* Why a row has no press: the server's sentence, asked for rather than printed in every row. */
.bdc-why { display: inline-block; max-width: 32ch; text-align: right; }
.bdc-why > summary { cursor: pointer; list-style: none; font-size: 11.5px; font-weight: 600; color: var(--nv2-ink-3); }
.bdc-why > summary::-webkit-details-marker { display: none; }
.bdc-why[open] > summary { color: var(--nv2-ink-2); margin-bottom: 3px; }
.bdc-why .bdc-sub { text-align: left; }

/* The per-row disclosure: one row of the card, a form card when it is open. */
.bdc-row-disclosure { border-top: 1px solid var(--nv2-line-2); }
.bdc-row-disclosure > summary { display: flex; align-items: baseline; gap: 10px; padding: 12px 16px; font-size: 12.5px; }
.bdc-row-disclosure[open] > summary { margin-bottom: 0; background: var(--nv2-panel-2); border-bottom: 1px solid var(--nv2-line-2); }
.bdc-row-disclosure > .nv2-form-card { border: 0; border-radius: 0; }
.bdc-disclosure-hint { font-size: 12px; font-weight: 500; color: var(--nv2-ink-3); }

/* Counter Customers: the walk-in form as a card, the person head, the facts band. */
.bdc-walk-in .bdc-disclosure > summary { padding: 7px 14px; border: 1px solid var(--nv2-line); border-radius: 999px; background: var(--nv2-panel); }
.bdc-walk-in .bdc-disclosure > form { margin-top: 10px; padding: 16px 18px 0; border: 1px solid var(--nv2-line); border-radius: var(--nv2-radius); background: var(--nv2-panel); overflow: hidden; }
.bdc-walk-in .bdc-disclosure > form > .nv2-form-footer { margin: 4px -18px 0; }
.bdc-person { display: inline-flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.bdc-person-name { font-family: var(--nv2-font-display); font-size: 18px; font-weight: 700; line-height: 1.25; letter-spacing: -0.01em; color: var(--nv2-ink); }
.bdc-facts-band { padding: 14px 16px; background: var(--nv2-panel-2); border-bottom: 1px solid var(--nv2-line-2); }
.bdc-dl-end { display: inline-flex; align-items: center; gap: 10px; }
.bdc-notice-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 8px; }

/* The one modal the bureau keeps: Void a receipt. */
.bdc-modal-backdrop { position: fixed; inset: 0; z-index: 1050; display: flex; align-items: center; justify-content: center; padding: 16px; background: rgba(15, 23, 42, 0.45); }
.bdc-modal { width: 100%; max-width: 560px; max-height: calc(100vh - 32px); overflow: auto; background: var(--nv2-panel); border-radius: var(--nv2-radius-lg); box-shadow: var(--nv2-shadow-xl); }
.bdc-modal-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 14px 20px; border-bottom: 1px solid var(--nv2-line-2); }
.bdc-modal-title { font-family: var(--nv2-font-display); font-size: 15px; font-weight: 700; color: var(--nv2-ink); }
.bdc-modal-body { padding: 16px 20px; display: flex; flex-direction: column; gap: 12px; }
.bdc-btn-icon { padding: 5px 8px; border-color: transparent; background: transparent; box-shadow: none; }

/* The layout's refusal card (app/routes/bureau.jsx). */
.bdc-refusal-title { font-family: var(--nv2-font-display); font-size: 16px; font-weight: 700; color: var(--nv2-ink); margin-bottom: 6px; }

@media (max-width: 640px) {
  .bdc-toolbar .bdc-filters .nv2-field { flex: 1 1 100%; }
  .bdc-toolbar .bdc-filters > .nv2-btn { width: 100%; justify-content: center; }
  .bdc-row-actions { justify-content: flex-start; }
  .bdc-section-body.is-flush > .nv2-empty-card { margin: 12px; }
  .bdc-walk-in .bdc-disclosure > form { padding: 14px 14px 0; }
  .bdc-walk-in .bdc-disclosure > form > .nv2-form-footer { margin: 4px -14px 0; }
}

/* -- measured on the rendered pages (flow/BD-registers, 2026-09-16) -------------
   Three things made a bureau table wider than the screen it is read on, and the
   plan names the symptom: a register must not scroll sideways at 1280.

   1. A FLEX ITEM WILL NOT SHRINK BELOW ITS CONTENT unless it is told it may. The
      page root and the card body are flex columns, so the table card inherited the
      table's own min-content width and the WHOLE PAGE grew: measured 514px of
      document in a 400px viewport before this rule.
   2. Sixteen pixels of padding a side over seven columns is 224px of air.
      MEASURED 2026-09-16 (the 856 after-look): THE PADDING RULE BELOW NEVER
      TAKES EFFECT, and this line banked a saving it has never made. The
      computed padding on a bureau cell is still 16px: `.nv2-table tbody td`
      and `.nv2-table thead th` weigh (0,1,2) and beat `.bdc-table td`
      (0,1,1). Every register on this branch was measured and folded WITH the
      real 16px and fits the 854px card without it ever biting. Making it bite
      is worth roughly 8px a column -- about 48px on a six-column register --
      but it re-flows every bureau table, so it is a MEASURED follow-up, not a
      silent one. Do not delete the rule, and do not give it teeth, without
      re-measuring all nine routes at CONTENT=856.
   3. A second fact under a cell must wrap rather than set the column width.
   The wrapping actions cell keeps the presses inside their column instead of
   pushing Status off the right edge. */
.bdc > *, .bdc-section > *, .bdc-section-body > * { min-width: 0; }
.bdc-table th, .bdc-table td { padding-left: 12px; padding-right: 12px; }
.bdc-table .bdc-sub { max-width: 24ch; }
.bdc-table td.is-actions { max-width: 150px; white-space: normal; }
/* A PILL THAT WRAPS MUST STILL READ AS A STATE. Pills in a stacked cell are allowed to
   wrap because some of these states are the service's own sentences and cannot be
   shortened to fit a column — "Void waiting for a second person" is the phrase for a void
   a second person has not yet agreed to, and "Bought from customer" is the side of the
   deal. At the pill's 999px radius a wrapped pill reads as a balloon rather than a tag,
   and the dot, centred against the whole box, drifts to the middle of the left edge. The
   colour, the dot and the words are untouched; only the shape is told it may take more
   than one line: a radius that survives three of them, the dot pinned to the FIRST line,
   and a box that can never be wider than the cell that holds it. */
.bdc-cell-stack .nv2-pill {
  white-space: normal;
  text-align: left;
  border-radius: 7px;
  align-items: flex-start;
  line-height: 1.35;
  padding-block: 4px;
  max-width: 100%;
}
.bdc-cell-stack .nv2-pill::before { flex: 0 0 auto; margin-top: 4px; }
/* The standing sentence belongs UNDER the lede row: the kit gives it a 100% basis,
   but a shrinkable item shares the line instead of wrapping onto its own. */
.bdc-standing { flex-shrink: 0; }
/* Four registers of tab will not fit a phone in one row: measured, the strip (not the
   table) was what made a 400px viewport render a 514px document. */
.bdc .nv2-tab-bar { flex-wrap: wrap; }
/* A padded block that is ALSO a two-up: .bdc-pad makes it a flex column and would win on
   source order alone, which stacked the two transfer forms and left half the card empty. */
.bdc-two-up.bdc-pad { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; align-items: start; }
@media (max-width: 991px) { .bdc-two-up.bdc-pad { grid-template-columns: 1fr; } }
/* MEASURED, and the reason the earlier flex-shrink fix was not enough: the kit gives the
   standing line a 100% flex basis AND a 76ch max-width, and the max-width clamps the
   hypothetical size the line-breaking uses — so at 1036px of card the sentence fitted
   beside the lede and shared its row (at 744px it wrapped, which is why it looked fixed).
   A min-width of 100% cannot be clamped, so the standing sentence sits under the row at
   every width, which is what S1 asks for. */
.bdc-standing { min-width: 100%; }

/* THE EMPTY-STATE SENTENCE WAS NOT CENTRED, AND THE CAUSE IS TWO RULES OF EQUAL WEIGHT.
   The kit opens with a blanket `.bdc p { margin: 0 }` (a paragraph reset, so section prose
   does not inherit the theme's bottom margin). The v2 kit centres an empty card's message
   with `.nv2-empty-card p { max-width: 380px; margin: 0 auto }`. Both selectors weigh
   (0,1,1), the reset is declared later, so it wins and the auto margins die: the message
   keeps its max-width but sits FLUSH LEFT inside a centred card, while the icon and the
   title above it are centred. Measured on Counter Customers: card centre 400px, icon 400,
   title 400, message 304 — off by 96px on all three empty states, and the same everywhere
   in the console a .bdc page draws an EmptyState. Restoring the centring alone, at a
   weight the reset cannot beat. FOR THE FOLD: this belongs beside the reset in the kit
   block rather than in a page branch's addendum — it is the kit's own regression. */
.bdc .nv2-empty-card p { margin-inline: auto; }
/* The limits cell may take two lines so the column can shrink to its widest word — see
   the note beside it in stock.jsx. Right-aligned still, because it is a figure. */
.bdc-table td.is-limits { white-space: normal; }

/* ═══════════════════════════════════════════════════════════════════════════
   BD-AFTER-COUNTER — the four counter routes, re-measured at the console's REAL
   content column (flow/bd/after-counter, 2026-09-16)

   THE MEASUREMENT THIS BLOCK ANSWERS. Every earlier pass on these pages was taken
   inside an SSR harness whose frame was 924–1128px wide. The console's content
   column at a 1280px browser is 856px — 1280 less the 72px rail, the 296px hub
   panel and .nv2-content's 28px a side — and the card inside it is 854. Measured
   there, four registers on these pages were wider than the card that holds them
   and lost their right-hand columns off the edge with no scroll affordance:

     /bureau/till     positions              1035px  (lost Difference and Status)
     /bureau/till     differences to decide   937px  (lost Decision)
     /bureau/buy      bought today            949px  (lost Status)
     /bureau/day-end  tie-out in notes        936px  (lost Ties out)
     sell + buy       the drawer panel        333px in a 277px box (lost the rate)

   The remedy is the plan's own — the SUB-LINE FOLD, in the routes — so almost
   nothing is needed here: a column that is a second fact about another column
   becomes a BdcSub under that column's cell, and .bdc-sub / .bdc-cell-stack
   already carry it. What IS needed is below, and only this.
   ═══════════════════════════════════════════════════════════════════════════ */

/* THE STATE COLUMN IS SIZED FOR THE LONGEST SENTENCE THE TILL CAN SEND, NOT FOR
   THE SHORTEST. bureau/till's statusBadge draws one of exactly four states, and
   the longest is "Waiting for a second person" — 27 characters, which at the
   pill's 11px uppercase with its dot and padding is about 245px on one line. It
   is an operator sentence and is not shortened to fit a column, so the pill takes
   more than one line and this floor is what stops the column collapsing under it.
   Measured before this rule: the pill ran past the card's right edge even in the
   wider harness.

   848, AND A CLAIM CORRECTED. This floor was 160px, and the sentence above used
   to end "a floor wide enough that it never takes three [lines]" - crediting the
   FLOOR with the line count. Measured in the real 846px card (the 848px content
   column less the card's two 1px edges), the floor does not govern it at all:
   with "Waiting for a second person" in the cell the pill renders at exactly 48px
   tall at a floor of 176px, of 160px, of 148px AND of 128px - the same height
   every time - while the column itself is sized 192/176/167/163px by the TABLE's
   own width distribution. Once the table fits, the distribution is what gives the
   sentence its room; the floor's only job is to stop the column collapsing, and
   between 128 and 176 it changes nothing a reader can see.

   So 160px was buying nothing it was credited with, while sitting 92.78px above
   the column's real min-content (83.22px, measured) - and the till register's
   minimum came to 853.13px inside an 846px card: SEVEN PIXELS OFF THE RIGHT EDGE,
   carrying away Difference and Status, the two columns the page exists to show.

   148px takes those seven pixels back with 4.87px to spare (841.13px), and the
   longest sentence renders at 48px after exactly as it did before - measured both
   ways, unchanged. The Status column was the one column here with room to give,
   and giving it costs no other route a pixel. */
.bdc-till .bdc-table.is-dense th.bdc-till-state,
.bdc-till .bdc-table.is-dense td.bdc-till-state { min-width: 148px; white-space: normal; }

/* A stacked cell that IS the cell needs no top margin — .bdc-cell-stack's 4px is
   for a stack that follows a figure (the receipt's pills, the buy register). */
.bdc-table td > .bdc-cell-stack:first-child { margin-top: 0; }

/* AN E-MAIL IS ONE UNBREAKABLE WORD. The teller under a difference is
   "TELLER Staging (teller@staging.nobleneo.com)"; .bdc-sub wraps at 24ch, but a
   44-character address has no break in it, so without this the sub sets the
   column's width and the fold buys nothing. The address is the identity the
   difference is decided against and is not truncated — it wraps. */
.bdc-table .bdc-sub.bdc-till-teller { overflow-wrap: anywhere; }

/* MOVE NOTES ON THIS TILL IS TWO ACTS, AND IS DRAWN AS TWO. The control was one
   Field in a three-up row inside an 854px card: a Currency select across a third
   of the width and two thirds blank beside it, for all five of the controls. Pick
   the currency on the left, count that currency's notes in the room on the right
   (before one is chosen, the line that says the notes will appear there). At
   phone width they stack, which is the same order read down. */
.bdc-till-pick { display: grid; grid-template-columns: 236px minmax(0, 1fr); gap: 20px; align-items: start; }
.bdc-till-pick > .nv2-field-row { margin-bottom: 0; }
@media (max-width: 720px) {
  .bdc-till-pick { grid-template-columns: 1fr; gap: 14px; }
}

/* THE RUNNING TOTAL IS A TOTAL, AND NOW LOOKS LIKE ONE. "Notes picked: 0.00 EUR."
   is the answer to the whole ladder above it, and it was drawn as a flat grey
   strip in ink-2 at 12.5px — the one element left on Sell and Buy that read as
   markup nobody had styled. It keeps the page's own words, byte for byte, and
   takes the shape a sum has carried on paper since before there were screens: the
   rule across the top of the column it adds up, the figure in the ink the page
   reserves for a figure, and the numerals tabular so a changing count does not
   shift the line. */
.bdc-ladder-total {
  padding: 11px 14px;
  border: 1px solid var(--nv2-line);
  border-top: 2px solid var(--nv2-ink);
  background: var(--nv2-panel-2);
  font-size: 13px; font-weight: 700;
  color: var(--nv2-ink);
  font-variant-numeric: tabular-nums;
}
.bdc-ladder-total strong { font-family: var(--nv2-font-display); font-weight: 800; }

/* FLOORS FOR THE TWO COLUMNS THAT NOW CARRY SUB-LINES, measured on the rendered
   page. A folded cell is only as good as the room its sub-line gets: at the width
   the table's own distribution gave them, "Top-ups 50,000.00 INR" broke between
   the figure and its currency code, which is the one place a money line must not
   break. The floors are what those two lines need; the Status column above has
   room to give and every other column is unchanged. */
.bdc-till .bdc-table.is-dense th.bdc-till-fig,
.bdc-till .bdc-table.is-dense td.bdc-till-fig { min-width: 118px; }
/* AND WHERE A SUB-LINE STILL HAS TO WRAP, IT BREAKS AFTER THE LABEL, NEVER INSIDE
   THE FIGURE. "Top-ups 50,000.00 INR" wants 148px and "Expected 200,000.00 PKR"
   168px; seven columns in 854 cannot give both of them that and still leave the
   state cell room for the longest sentence it can carry. So the figure is one
   unbreakable run: what wraps is the label off the front of it, and a money line
   is never split from the currency it is in. */
.bdc-table .bdc-sub .bdc-sub-fig { white-space: nowrap; }

/* THE DECISION CELL HOLDS A CONTROL, NOT A FIGURE, so it is sized for the control:
   the note box, Accept and Reject on ONE row. With the column left to the table's
   own distribution the two presses wrapped under the box, which reads as two
   separate decisions rather than one either/or. */
.bdc-till .bdc-table th.bdc-till-decide,
.bdc-till .bdc-table td.bdc-till-decide { min-width: 382px; }

/* THE RIBBON'S PILLS ARE THE SERVICE'S OWN WORDS TOO. Day End's five tiles are
   ~115px wide at the console's real content column and two of them carry a pill:
   "Raised for Finance" rendered past the tile's right edge as "RAISED FOR FINAN"
   and "Count again" spilled over the border beside it. Same remedy as a pill in a
   stacked cell — the words are untouched and the shape is told it may take a
   second line, with the dot pinned to the first. */
.bdc-ribbon.is-counter .nv2-stat-value .nv2-pill {
  white-space: normal;
  text-align: left;
  border-radius: 7px;
  align-items: flex-start;
  line-height: 1.3;
  padding-block: 3px;
  max-width: 100%;
}
.bdc-ribbon.is-counter .nv2-stat-value .nv2-pill::before { flex: 0 0 auto; margin-top: 4px; }
/* The limits cell may take two lines so the column can shrink to its widest word — see
   the note beside it in stock.jsx. Right-aligned still, because it is a figure. */
.bdc-table td.is-limits { white-space: normal; }

/* ═══════════════════════════════════════════════════════════════════════════
   BD-AFTER-REGISTERS — the three registers at the console's REAL content column
   (bd-fix/BRIEF.md, measured 2026-09-16 on the folded tree)

   THE NUMBER EVERY EARLIER PASS GOT WRONG. Nine bureau routes were signed off
   inside an SSR harness frame of 924–1128px. The console gives a card 856px at a
   1280px browser — 1280 − 72 (rail) − 296 (hub panel) − 28 − 28 (.nv2-content) —
   and the card gives its table 854. Measured at 856 before this block:

     bureau-stock-transfers-table   941  over by 87  (6 columns)
     bureau-receipts-table          940  over by 86  (7 columns)
     bureau-stock-positions-table   927  over by 73  (7 columns)

   A column past the right edge with no scroll bar to say so is the owner's
   original complaint, and the three that fell off were the three that matter:
   Status on positions (the below-minimum warning), Status on transfers (a bag
   still on the road), Actions on receipts (Open / Print again / Void).

   THE COLUMNS WERE FOLDED IN THE ROUTES, NOT SQUEEZED HERE. Available folds
   under On hand, Limits under Status, Sent at under Reference, Branch and teller
   under Receipt — each a second fact under the fact it belongs to, the remedy
   BdcTable.jsx documents. This block is only the four floors and the one shape
   that folding cannot state: which columns get the room the fold freed, and a
   pill that must not read as a press.
   ═══════════════════════════════════════════════════════════════════════════ */

/* A BRANCH IS A BUSINESS NAME AND NEEDS THE ROOM THE TABLE NOW HAS. With two
   columns folded away, the positions register carries ~200px of slack, and an
   auto table layout spends slack on the columns with the largest max-content —
   which is never the one wrappable cell. "Fellworth / Money / Ltd" read down
   three lines beside half a row of air. A min-width is a floor, not a width: a
   longer business name still wraps rather than pushing the register off the
   card. */
.bdc-stock .bdc-table td.is-branch { min-width: 168px; }
/* The limits figure is no longer a column of its own — it is the sub-line under
   the status it explains ("Below minimum", and the minimum it is below). It is
   still a figure, so it still gets tabular numerals; .bdc-sub already lets it
   wrap, which is what the retired `td.is-limits { white-space: normal }` was
   for. */
.bdc-table .bdc-sub.is-limits { font-variant-numeric: tabular-nums; }
/* RECEIPTS: THE THREE COLUMNS THE OVERFLOW WAS STARVING, MEASURED AT 856.

   Receipt — the side of the deal lives here and "Bought from customer" is a
   193px tag. At 177px of content the cell was sixteen pixels short of it, so the
   one thing on the row that says which way the notes went wrapped into a 179×38
   grey box under the receipt number and read as a button to press.

   Customer — a customer's name is what a teller reads the row for, and at 103px
   "Rowan / Wintermere" broke across two lines while the table hung 86px off the
   right edge of the card.

   Status — measured: "Void waiting for a second person" is a 245px tag, and in a
   128px column it folded into a 96×82px FOUR-line balloon that drove the row to
   169px. A pill is a tag; four lines of it is a paragraph. The words are the
   void door's own and are frozen, and a column 277px wide cannot be had in an
   854px register that also carries a receipt number, two money columns and three
   presses — so the long standing left the cell for a full-width line under the
   row (.bdc-row-standing, below) and the column keeps only the tag a reader
   scans for. It needs no floor of its own now.

   A floor, not a width: a longer name still wraps rather than pushing the
   register off the card. Padding in a .bdc-table cell is 16px a side (the kit's
   own `.nv2-table tbody td`/`thead th` beat `.bdc-table th, .bdc-table td` on
   specificity), so each floor below costs itself plus 32. */
.bdc-receipts .bdc-table th.is-receipt,
.bdc-receipts .bdc-table td.is-receipt { min-width: 194px; }
/* 848: at 116px the register's minimum was 846.86px inside an 846px card - over
   by a pixel, and this is the column with the room to give it. Its real
   min-content is 102.63px (the longest word of a name plus the 32px of padding),
   so 110px is still a floor ABOVE the content, and a longer name still wraps
   rather than pushing the register off the card - which is all this floor ever
   promised. 840.86px now, 5.14px of headroom. */
.bdc-receipts .bdc-table th.is-customer,
.bdc-receipts .bdc-table td.is-customer { min-width: 110px; }

/* THE SIDE OF THE DEAL IS A TAG, NOT A PRESS. .bdc-cell-stack squares a pill off
   to a 7px radius so a wrapped service sentence does not read as a balloon. The
   side of the deal is never a sentence — it is one of exactly two phrases,
   "Sold to customer" or "Bought from customer" — and at 7px, filled grey and
   179px wide under the receipt number it read as a button somebody could press.
   It keeps the tag's own radius, and the Receipt floor above holds it on one
   line at every width this register is read at. */
.bdc-receipts .bdc-cell-stack.bdc-deal-side .nv2-pill { border-radius: 999px; }

/* THE STANDING ROW — the second <tr> under a receipt whose standing has more to
   say than a tag. It is a .bdc-row-detail (the kit's grey band directly under
   the row, inside the same test slice) but it carries no <details>: a state an
   operator must act on is not something to ask for, and a void waiting on a
   second person is exactly that. The line is a row, not a stack, so the tag
   keeps its own nowrap width and the request code sits beside it. */
.bdc-standing-line { display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 12px; }
.bdc-standing-line .bdc-sub { margin-top: 0; max-width: 72ch; }

/* ═════════════════════════════════════════════════════════════════════════════
   ===== BD-AFTER-RATESREPORTS — the 856 after-look, /bureau/rates + /bureau/reports
   Measured at the console's REAL content column: 1280 − 72 (rail) − 296 (hub
   panel) − 28 − 28 (.nv2-content) = 856, wrapper 854. Before this block the rate
   board was 985 (over by 131) and the HMRC record 4,963 (over by 4,109). Nothing
   here shrinks a font or a padding to reach 854 — the JSX folds a second fact
   under the fact it belongs to and puts the rest of a record in the row under the
   row; what follows is only how that shape is inked.
   ═════════════════════════════════════════════════════════════════════════════ */

/* -- A DISCLOSURE SUMMARY IS A QUIET AFFORDANCE, NOT A LINK ------------------
   `.bdc-row-detail summary` was set in the hub accent — rgb(67,97,238) — at
   11.5px/700 with letter-spacing, flush left across the table. On the Rate Board
   that is twelve of them for six currencies, and the register read as a list of
   links to twelve other pages. A disclosure goes nowhere: it opens the row it is
   already in. So it takes the hint ink, a normal weight, and a CARET — drawn in
   borders, not a character, so it adds nothing to the accessibility tree — which
   turns when the row opens. The summary WORDS are untouched, it is still a
   pointer target, and hover/focus bring it up to the reading ink so it still
   answers the mouse. */
.bdc-row-detail summary {
  color: var(--nv2-ink-3);
  font-weight: 600;
  letter-spacing: 0.01em;
  gap: 7px;
  width: fit-content;
}
.bdc-row-detail summary::before {
  content: '';
  flex: 0 0 auto;
  width: 0; height: 0;
  border-left: 4.5px solid currentColor;
  border-top: 3.5px solid transparent;
  border-bottom: 3.5px solid transparent;
  transition: transform 120ms ease;
}
.bdc-row-detail details[open] > summary::before { transform: rotate(90deg); }
.bdc-row-detail summary:hover,
.bdc-row-detail summary:focus-visible,
.bdc-row-detail details[open] > summary { color: var(--nv2-ink-2); }
.bdc-row-detail summary:focus-visible { outline: 2px solid var(--nv2-hub-accent, var(--nv2-brand)); outline-offset: 2px; }

/* -- THE HMRC RECORD: SEVEN COLUMNS, AND THE REST UNDER THE ROW --------------
   The three identity columns hold people's and branches' names, which may take
   two lines rather than hold a column open at their longest. `.bdc-reports
   .bdc-table td.is-wrap` sets a 26ch FLOOR for the wide prose columns of the
   other reports; on this table the same class means a name, so the floor comes
   off. Equal specificity, declared later, so this is the one that applies. */
.bdc-reports .bdc-hmrc td.is-wrap { min-width: 0; max-width: 20ch; }
/* A receipt number is a structured identifier, not a word: it may break after one
   of its own hyphens rather than hold the first column open at its full length. */
.bdc-reports .bdc-hmrc td.is-id {
  white-space: normal; overflow-wrap: normal; word-break: normal;
  /* 848, AND A CLAIM CORRECTED. This floor was 121px and called itself "the
     measured width of a receipt number ... the floor keeps it on ONE line".
     Re-measured in the shipped face on the shipped fixture, `BDC-FLW-00014112`
     is 133.69px on one line - WIDER THAN THE FLOOR - so 121px never kept it on
     one line, and the number was already breaking at its own hyphens, exactly as
     the second half of that sentence says it may. The floor's real job is the one
     it does do: stop the column collapsing to a stack of fragments.

     At 121px the record's minimum was 846.66px inside an 846px card, over by a
     pixel. 115px brings it to 840.66px with 5.34px of headroom, and it is still
     a floor and not a squeeze: 115 plus the 32px of padding makes the column
     147px, against the 87.45px that same column takes when the floor is lifted
     entirely - 59.55px of room still held open above what the content needs. */
  min-width: 115px;
}

/* The rest of a ticket: the export's own label over the export's own value, two
   to four pairs a row, inside the closed disclosure. A definition list because
   that is what it is — a name and the thing it names. */
.bdc-record {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  gap: 10px 20px;
  margin: 0;
}
.bdc-record > div { min-width: 0; }
.bdc-record dt {
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--nv2-ink-3);
  margin: 0 0 2px;
}
.bdc-record dd {
  margin: 0;
  font-size: 12.5px; line-height: 1.45;
  color: var(--nv2-ink);
  overflow-wrap: anywhere;
}
.bdc-record dd.is-num { font-family: var(--nv2-font-mono); font-variant-numeric: tabular-nums; }
.bdc-record dd.is-mono { font-family: var(--nv2-font-mono); font-size: 12px; }
.bdc-record dd.is-id { font-family: var(--nv2-font-display); font-weight: 700; }
/* The two long regulated sentences — CDD evidence, Retention — are prose and
   take the whole row rather than a 190px column of their own. */
.bdc-record > div.is-prose { grid-column: 1 / -1; }
.bdc-record dd.is-wrap { max-width: 78ch; }

/* Two sentences in the toolbar's left slot — what the file carries, and what the
   screen carries — stack; the kit's row would put them side by side. */
.bdc-reports .nv2-table-toolbar-left { flex-direction: column; align-items: flex-start; gap: 4px; }

/* -- 400px -------------------------------------------------------------------
   One column of pairs, and the names get the whole cell back. */
@media (max-width: 640px) {
  .bdc-record { grid-template-columns: 1fr; gap: 8px; }
  .bdc-reports .bdc-hmrc td.is-wrap { max-width: none; }
}
/* -- THE TOTAL ROW'S LABEL MAY WRAP -----------------------------------------
   `Total for the window` is four words in a `<th scope="row">`, and `.nv2-table
   th` is nowrap: 167px of min-content in column one of the Daily report, wider
   than any bureau day the column ever prints. It held that table at exactly its
   wrapper's width, so the moment the four sterling columns started saying their
   currency (see the money presenter in reports.jsx) the table went 3px over and
   the last column began to clip. A row label that wraps costs a line of height
   in ONE row and gives the register back fifty pixels; no word changes. */
.bdc-reports .bdc-table tfoot tr.bdc-total > th { white-space: normal; }

/* ===== end BD-AFTER-RATESREPORTS ========================================== */
