/* ============================================================
   PBC COMPONENTS  —  the approved visual vocabulary
   ------------------------------------------------------------
   Phase 2 of the UI redesign. Consumes pbc-tokens.css ONLY.
   Load order: pbc-tokens.css MUST come first.

   NAMESPACE
     Every class is prefixed `pbc-`. The app runs on Bootstrap;
     never style a bare .btn/.card/.table/.badge — that would
     reach into Bootstrap and break existing screens.

   RTL
     Written with logical properties (inline-start/end, padding-
     inline, margin-inline) so the same rules mirror correctly
     under <html dir="rtl"> for Arabic. No separate RTL sheet.

   RULES
     - No hardcoded colour, spacing, radius, or type size. Tokens only.
     - Every interactive element needs a :focus-visible ring.
     - Colour never carries meaning alone — always pair it with
       text or an icon (colour-blind + print safe).
   ============================================================ */

/* ==========================================================
   BASE
   ========================================================== */
.pbc-scope{
  font-family:var(--pbc-font-body);
  font-size:var(--pbc-text-md);
  line-height:var(--pbc-leading-normal);
  color:var(--pbc-ink-body);
  -webkit-font-smoothing:antialiased;
}
.pbc-h1,.pbc-h2,.pbc-h3{
  font-family:var(--pbc-font-heading);
  font-weight:var(--pbc-weight-heading);
  color:var(--pbc-ink-heading);
  letter-spacing:var(--pbc-tracking-tight);
  line-height:var(--pbc-leading-tight);
  margin:0;
}
.pbc-h1{font-size:var(--pbc-text-2xl)}
.pbc-h2{font-size:var(--pbc-text-xl)}
.pbc-h3{font-size:var(--pbc-text-lg);font-weight:var(--pbc-weight-semibold)}
.pbc-muted{color:var(--pbc-ink-muted)}
.pbc-faint{color:var(--pbc-ink-faint)}
.pbc-label-caps{
  font-size:var(--pbc-text-xs);
  font-weight:var(--pbc-weight-bold);
  letter-spacing:var(--pbc-tracking-caps);
  text-transform:uppercase;
  color:var(--pbc-ink-muted);
}

/* ==========================================================
   BUTTONS
   ========================================================== */
.pbc-btn{
  display:inline-flex;align-items:center;justify-content:center;
  gap:var(--pbc-space-2);
  height:var(--pbc-control-h);
  padding-inline:var(--pbc-space-5);
  border:var(--pbc-border-width) solid transparent;
  border-radius:var(--pbc-radius-btn);
  font-family:inherit;
  font-size:var(--pbc-text-base);
  font-weight:var(--pbc-weight-semibold);
  line-height:1;
  white-space:nowrap;
  cursor:pointer;
  text-decoration:none;
  transition:background-color var(--pbc-transition),
             border-color var(--pbc-transition),
             color var(--pbc-transition);
}
.pbc-btn:focus-visible{outline:none;box-shadow:var(--pbc-focus-ring)}
.pbc-btn[disabled],.pbc-btn.is-disabled{opacity:.5;cursor:not-allowed;pointer-events:none}

.pbc-btn--primary{background:var(--pbc-brand-600);color:var(--pbc-ink-on-brand);box-shadow:var(--pbc-shadow-sm)}
.pbc-btn--primary:hover{background:var(--pbc-brand-700);color:var(--pbc-ink-on-brand)}
.pbc-btn--secondary{background:var(--pbc-surface);color:var(--pbc-ink-body);border-color:var(--pbc-border)}
.pbc-btn--secondary:hover{border-color:var(--pbc-border-strong);background:var(--pbc-surface-hover);color:var(--pbc-ink-body)}
.pbc-btn--ghost{background:transparent;color:var(--pbc-ink-muted)}
.pbc-btn--ghost:hover{background:var(--pbc-surface-hover);color:var(--pbc-brand-accent)}
/* fill is danger-600, NOT 500: white on the bright 500 is 3.97:1, below AA. */
/* §K K-4.22 (§14.290, owner-approved 2026-08-07) — the fill is the PINNED
   call-decline pair, not the theme-flipping danger ramp. In light they are
   the SAME hexes (#B01818 / #8A1212), so nothing the owner approved moves;
   in dark, --pbc-danger-600 flips to #F2A3A3 — an INK colour — which is what
   painted every dark Delete/Not-approve button as a pale pink slab
   (§14.267 carry-over, now closed). White stays 7.02:1 on the fill. */
.pbc-btn--danger{background:var(--pbc-call-decline);color:var(--pbc-ink-on-brand)}
.pbc-btn--danger:hover{background:var(--pbc-call-decline-hover);color:var(--pbc-ink-on-brand)}
/* LOW-EMPHASIS DESTRUCTIVE (§K K-4.12). The system had only a FILLED danger
   button, which is too loud for a per-row "remove" that already sits behind a
   confirm — a field builder with six sections would have shown six red slabs.
   This keeps the red as a signal without shouting.
   ⚠ NEVER give this the matte finish: it has no fill, so the overlay's dark
   bottom stop would just print grey (see the --pbc-btn-matte note).
   `--pbc-danger-600` is an INK token that flips per theme (#B01818 light,
   #F2A3A3 dark) — correct here because this is text, not a fill. Measured
   7.02:1 light / 7.42:1 dark on the surface, and 5.78 / 5.38 on the hover. */
.pbc-btn--danger-quiet{background:transparent;color:var(--pbc-danger-600)}
.pbc-btn--danger-quiet:hover{background:var(--pbc-surface-hover);color:var(--pbc-danger-600)}
/* ★ --send: the chat composer's send button. A THIRD filled variant rather than
   a colour applied by hand inside pbc-chat.css, so it inherits the global matte
   finish and geometry like every other button (owner, 2026-07-29: "buttons are
   decided — matte, and it's already applied globally — so don't style chat's
   buttons by hand").
   The colour is the owner's decision to keep chat's original brighter blue for
   the things the USER sends. White on it is 5.58:1; the hover step is darker
   (7.13:1), never lighter — going lighter is what breaks white labels. */
.pbc-btn--send{background:var(--pbc-chat-mine);color:var(--pbc-ink-on-brand)}
.pbc-btn--send:hover{background:var(--pbc-chat-mine-hover);color:var(--pbc-ink-on-brand)}

/* ── MATTE FINISH (owner decision 2026-07-29) ─────────────────────────────
   See the `--pbc-btn-matte` block in pbc-tokens.css for what this is and how
   to retire it. Applied here ONLY to the two FILLED variants.
   --secondary, --ghost and --inverse are excluded on purpose: they are white
   or transparent, so the overlay's dark bottom stop would print grey shading
   onto a light button instead of shaping a colour. --inverse especially — it
   exists to stay bright against the login gradient (see its own note below).
   Uses `background-image`, never the `background` shorthand, so each variant
   keeps its own background-color and its own :hover colour change. */
.pbc-btn--primary,
.pbc-btn--danger,
.pbc-btn--send{
  background-image:var(--pbc-btn-matte);
  box-shadow:var(--pbc-btn-matte-lip),var(--pbc-shadow-sm);
}
/* ⚠ The :hover rules above use the `background` SHORTHAND, and the shorthand
   resets background-image to `none`. Without this the finish would flicker off
   the moment the pointer touched the button. Re-asserted rather than rewriting
   those hovers to background-color, so nothing existing changes behaviour. */
.pbc-btn--primary:hover,
.pbc-btn--danger:hover,
.pbc-btn--send:hover{ background-image:var(--pbc-btn-matte); }
.pbc-btn--sm{height:var(--pbc-control-h-sm);padding-inline:var(--pbc-space-3);font-size:var(--pbc-text-sm)}
.pbc-btn--lg{height:var(--pbc-control-h-lg);padding-inline:var(--pbc-space-6);font-size:var(--pbc-text-lg)}
.pbc-btn--icon{width:var(--pbc-control-h);padding-inline:0;flex:none}
.pbc-btn--icon.pbc-btn--sm{width:var(--pbc-control-h-sm)}
.pbc-btn--block{width:100%}

/* loading state — spinner replaces nothing, sits before the label */
.pbc-btn.is-loading{pointer-events:none;opacity:.75}
.pbc-btn.is-loading::before{
  content:'';width:14px;height:14px;flex:none;
  border:2px solid currentColor;border-top-color:transparent;
  border-radius:var(--pbc-radius-pill);
  animation:pbc-spin var(--pbc-duration-slow) linear infinite;
}
@keyframes pbc-spin{to{transform:rotate(360deg)}}

/* ==========================================================
   FORM CONTROLS
   ========================================================== */
.pbc-field{display:flex;flex-direction:column;gap:var(--pbc-space-1-5)}
.pbc-field__label{
  font-size:var(--pbc-text-sm);
  font-weight:var(--pbc-weight-semibold);
  color:var(--pbc-ink-heading);
}
/* small red text -> the deep red; the bright 500 is 3.97:1, below AA. */
.pbc-field__label .pbc-req{color:var(--pbc-danger-600);margin-inline-start:var(--pbc-space-0-5)}
.pbc-field__hint{font-size:var(--pbc-text-sm);color:var(--pbc-ink-muted)}
.pbc-field__error{
  font-size:var(--pbc-text-sm);color:var(--pbc-danger-600);
  display:flex;align-items:center;gap:var(--pbc-space-1-5);
}

.pbc-input,.pbc-select,.pbc-textarea{
  width:100%;
  padding-block:0;
  padding-inline:var(--pbc-space-3);
  height:var(--pbc-control-h);
  border:var(--pbc-border-width) solid var(--pbc-border);
  border-radius:var(--pbc-radius-btn);
  background:var(--pbc-surface);
  color:var(--pbc-ink-body);
  font-family:inherit;
  font-size:var(--pbc-text-base);
  transition:border-color var(--pbc-transition),box-shadow var(--pbc-transition);
}
.pbc-textarea{height:auto;min-height:96px;padding-block:var(--pbc-space-2-5);resize:vertical;line-height:var(--pbc-leading-normal)}
.pbc-input::placeholder,.pbc-textarea::placeholder{color:var(--pbc-ink-faint)}
.pbc-input:hover,.pbc-select:hover,.pbc-textarea:hover{border-color:var(--pbc-border-strong)}
.pbc-input:focus,.pbc-select:focus,.pbc-textarea:focus{
  outline:none;border-color:var(--pbc-brand-accent);box-shadow:var(--pbc-focus-ring);
}
.pbc-input[disabled],.pbc-select[disabled],.pbc-textarea[disabled]{
  background:var(--pbc-surface-soft);color:var(--pbc-ink-disabled);cursor:not-allowed;
}
.pbc-input.is-invalid,.pbc-select.is-invalid,.pbc-textarea.is-invalid{border-color:var(--pbc-danger-500)}
.pbc-input.is-invalid:focus{box-shadow:0 0 0 var(--pbc-focus-ring-width) var(--pbc-danger-100)}

/* select needs its own caret, mirrored for RTL */
.pbc-select{
  appearance:none;
  padding-inline-end:var(--pbc-space-8);
  background-image:linear-gradient(45deg,transparent 50%,currentColor 50%),
                   linear-gradient(135deg,currentColor 50%,transparent 50%);
  background-size:5px 5px,5px 5px;
  background-repeat:no-repeat;
  background-position:right var(--pbc-space-4) center,
                      right calc(var(--pbc-space-4) - 5px) center;
  color:var(--pbc-ink-body);
}
[dir="rtl"] .pbc-select{
  background-position:left calc(var(--pbc-space-4) - 5px) center,
                      left var(--pbc-space-4) center;
}

/* search input with leading icon */
.pbc-search{position:relative;display:flex;align-items:center}
.pbc-search .pbc-input{padding-inline-start:var(--pbc-space-10)}
.pbc-search__icon{
  position:absolute;inset-inline-start:var(--pbc-space-3);
  color:var(--pbc-ink-faint);pointer-events:none;display:flex;
}

/* checkbox / radio.
   Styled for BOTH the labelled .pbc-check wrapper and bare checkboxes
   inside a permission matrix cell — the matrix has no room for labels,
   and unstyled native boxes there looked broken next to styled ones. */
/* §K K-4.14 — .pbc-table--ticks is the THIRD consumer of this same look: a
   table whose cells hold a bare checkbox or radio under a column heading, with
   no room for a per-control label (the status editors' Default / Terminal /
   Cancellation columns). It is added to the selector lists below rather than
   given its own declarations, so there is still exactly ONE definition of what
   a tick looks like.
   ★ Ticks here are deliberately LARGER (owner, 2026-08-03) — set as a scoped
   custom property so the shared width/height below need no variant.
   ★ A RADIO in this context stays SQUARE and wears the same checkmark as its
   neighbours (owner: "they should all be the same, not the circle"). That is
   automatic: the round-radio overrides are scoped to .pbc-check, which this is
   not — so do NOT add .pbc-table--ticks to those two rules. The input stays a
   real radio, which is what keeps "exactly one default" working. */
.pbc-table--ticks{--pbc-tick:22px}
.pbc-table--ticks td input[type="checkbox"],
.pbc-table--ticks td input[type="radio"]{cursor:pointer}
.pbc-table--ticks td input::after{width:12px;height:12px}

.pbc-check{display:inline-flex;align-items:center;gap:var(--pbc-space-2-5);cursor:pointer;font-size:var(--pbc-text-base)}
.pbc-check input,
.pbc-matrix td input[type="checkbox"],
.pbc-table--ticks td input[type="checkbox"],
.pbc-table--ticks td input[type="radio"]{
  appearance:none;margin:0;flex:none;
  width:var(--pbc-tick);height:var(--pbc-tick);
  border:1.5px solid var(--pbc-border-strong);
  background:var(--pbc-surface);
  border-radius:var(--pbc-radius-xs);
  cursor:pointer;
  display:grid;place-content:center;
  transition:background-color var(--pbc-transition),border-color var(--pbc-transition);
}
.pbc-check input[type="radio"]{border-radius:var(--pbc-radius-pill)}
.pbc-check input::after,
.pbc-matrix td input[type="checkbox"]::after,
.pbc-table--ticks td input::after{
  content:'';width:11px;height:11px;transform:scale(0);
  transition:transform var(--pbc-duration-instant) var(--pbc-ease-out);
  background:var(--pbc-ink-on-brand);
  clip-path:polygon(14% 44%,0 65%,50% 100%,100% 16%,80% 0,43% 62%);
}
.pbc-check input[type="radio"]::after{
  clip-path:none;border-radius:var(--pbc-radius-pill);width:8px;height:8px;
}
.pbc-check input:checked,
.pbc-matrix td input[type="checkbox"]:checked,
.pbc-table--ticks td input:checked{background:var(--pbc-brand-600);border-color:var(--pbc-brand-600)}
.pbc-check input:checked::after,
.pbc-matrix td input[type="checkbox"]:checked::after,
.pbc-table--ticks td input:checked::after{transform:scale(1)}
.pbc-check input:focus-visible,
.pbc-matrix td input[type="checkbox"]:focus-visible,
.pbc-table--ticks td input:focus-visible{outline:none;box-shadow:var(--pbc-focus-ring)}
.pbc-check input[disabled],
.pbc-matrix td input[type="checkbox"][disabled],
.pbc-table--ticks td input[disabled]{background:var(--pbc-surface-soft);border-color:var(--pbc-border);cursor:not-allowed}

/* toggle switch */
.pbc-switch{display:inline-flex;align-items:center;gap:var(--pbc-space-2-5);cursor:pointer}
.pbc-switch input{
  appearance:none;margin:0;flex:none;position:relative;
  width:var(--pbc-switch-w);height:var(--pbc-switch-h);
  border-radius:var(--pbc-radius-pill);
  background:var(--pbc-neutral-500);cursor:pointer;
  transition:background-color var(--pbc-transition);
}
/* Knob moves via inset-inline-start, NOT translate: a directional
   translate needs a [dir="rtl"] override, which silently failed to
   apply and left the knob sliding the wrong way in Arabic. A logical
   inset mirrors on its own, with no override to forget. */
.pbc-switch input::after{
  content:'';position:absolute;top:3px;inset-inline-start:3px;
  width:calc(var(--pbc-switch-h) - 6px);height:calc(var(--pbc-switch-h) - 6px);
  border-radius:var(--pbc-radius-pill);
  background:var(--pbc-surface);box-shadow:var(--pbc-shadow-xs);
  transition:inset-inline-start var(--pbc-transition);
}
.pbc-switch input:checked{background:var(--pbc-brand-600)}
.pbc-switch input:checked::after{
  inset-inline-start:calc(var(--pbc-switch-w) - var(--pbc-switch-h) + 3px);
}
.pbc-switch input:focus-visible{outline:none;box-shadow:var(--pbc-focus-ring)}
.pbc-switch input[disabled]{opacity:.5;cursor:not-allowed}
.pbc-switch__text{font-size:var(--pbc-text-base);color:var(--pbc-ink-body)}

/* ==========================================================
   PILLS / BADGES  — outline style, colour + text always paired
   ========================================================== */
.pbc-pill{
  display:inline-flex;align-items:center;gap:var(--pbc-space-1-5);
  border-radius:var(--pbc-radius-pill);
  padding-block:var(--pbc-space-1);
  padding-inline:var(--pbc-space-3);
  font-size:var(--pbc-text-sm);
  font-weight:var(--pbc-weight-semibold);
  line-height:var(--pbc-leading-snug);
  border:var(--pbc-border-width) solid transparent;
  white-space:nowrap;
}
.pbc-pill__dot{width:7px;height:7px;border-radius:var(--pbc-radius-pill);background:currentColor;flex:none}
.pbc-pill--info   {background:var(--pbc-info-100);   color:var(--pbc-info-600);   border-color:var(--pbc-info-border)}
.pbc-pill--warning{background:var(--pbc-warning-100);color:var(--pbc-warning-600);border-color:var(--pbc-warning-border)}
.pbc-pill--success{background:var(--pbc-success-100);color:var(--pbc-success-600);border-color:var(--pbc-success-border)}
.pbc-pill--danger {background:var(--pbc-danger-100); color:var(--pbc-danger-600); border-color:var(--pbc-danger-border)}
.pbc-pill--neutral{background:var(--pbc-neutral-100);color:var(--pbc-neutral-600);border-color:var(--pbc-neutral-border)}
/* There is deliberately NO gold/accent pill. Owner chose "no warm accent"
   (2026-07-22): "needs attention" is the WARNING pill — a semantic state,
   not a decorative colour. Adding a 6th accent pill would reintroduce a
   colour that means nothing on its own. */

/* count badge */
.pbc-count{
  display:inline-flex;align-items:center;justify-content:center;
  min-width:20px;height:20px;padding-inline:var(--pbc-space-1-5);
  border-radius:var(--pbc-radius-pill);
  background:var(--pbc-neutral-100);color:var(--pbc-ink-muted);
  font-size:var(--pbc-text-xs);font-weight:var(--pbc-weight-bold);
}
.pbc-count--brand{background:var(--pbc-brand-600);color:var(--pbc-ink-on-brand)}
/* fill is danger-600, NOT 500: white on the bright 500 is 3.97:1, below AA. */
.pbc-count--danger{background:var(--pbc-danger-600);color:var(--pbc-ink-on-brand)}

/* ==========================================================
   AVATAR
   ========================================================== */
.pbc-avatar{
  width:var(--pbc-avatar);height:var(--pbc-avatar);flex:none;
  border-radius:var(--pbc-radius-pill);
  background:linear-gradient(135deg,var(--pbc-brand-900),var(--pbc-brand-500));
  color:var(--pbc-ink-on-brand);
  display:flex;align-items:center;justify-content:center;
  font-size:var(--pbc-text-sm);font-weight:var(--pbc-weight-bold);
  overflow:hidden;
}
.pbc-avatar img{width:100%;height:100%;object-fit:cover}
.pbc-avatar--sm{width:var(--pbc-avatar-sm);height:var(--pbc-avatar-sm);font-size:var(--pbc-text-xs)}
.pbc-avatar--lg{width:var(--pbc-avatar-lg);height:var(--pbc-avatar-lg);font-size:var(--pbc-text-base)}
.pbc-avatar-stack{display:flex}
.pbc-avatar-stack .pbc-avatar{border:2px solid var(--pbc-surface);margin-inline-start:-9px}
.pbc-avatar-stack .pbc-avatar:first-child{margin-inline-start:0}

/* ==========================================================
   CARD
   ========================================================== */
.pbc-card{
  background:var(--pbc-surface);
  border:var(--pbc-border-width) solid var(--pbc-border);
  border-radius:var(--pbc-radius-card);
  box-shadow:var(--pbc-shadow-sm);
}
.pbc-card__head{
  display:flex;align-items:center;gap:var(--pbc-space-3);
  padding:var(--pbc-space-5) var(--pbc-card-pad);
  border-bottom:var(--pbc-border-width) solid var(--pbc-border-subtle);
}
.pbc-card__title{font-size:var(--pbc-text-lg);font-weight:var(--pbc-weight-semibold);color:var(--pbc-ink-heading)}
.pbc-card__body{padding:var(--pbc-card-pad)}
.pbc-card__foot{
  display:flex;align-items:center;gap:var(--pbc-space-3);
  padding:var(--pbc-space-4) var(--pbc-card-pad);
  border-top:var(--pbc-border-width) solid var(--pbc-border-subtle);
  background:var(--pbc-surface-soft);
  border-end-start-radius:var(--pbc-radius-card);
  border-end-end-radius:var(--pbc-radius-card);
}
/* ==========================================================
   ⚠⚠ A FLUSH BODY MUST CLIP, OR THE CARD'S ROUNDED CORNERS ARE
   PAINTED OVER SQUARE. Owner-reported 2026-08-08 (§K K-4.26).
   ----------------------------------------------------------
   `.pbc-card` is rounded (16px) but does NOT clip — deliberately,
   because things inside it are allowed to escape. A padded
   `.pbc-card__body` is safe: nothing reaches the corner. A FLUSH
   body is the opposite — its content sits directly on the card's
   edge, and everything in there paints an opaque background the
   full width of the box:
       .pbc-table thead th      -> --pbc-surface-soft
       .pbc-table--zebra tr     -> --pbc-surface / --pbc-row-stripe
       tbody tr:hover           -> --pbc-row-hover
       .pbc-row / .pbc-row:hover
   Each of those is a SQUARE rectangle, so it covers the card's
   curve and the card reads as a square box with a rounded outline
   behind it.

   ★ THIS WAS ALWAYS TRUE — it only became VISIBLE when the outline
   went from 1.26:1 to 2.37:1 in this same slice. At the old
   strength there was no line to see the mismatch against. Treat a
   contrast change as a magnifying glass over every geometry bug
   the old faintness was hiding.

   THE FIX IS ON THE BODY, NOT THE CARD, AND NOT THE TABLE:
   · not `.pbc-card{overflow:hidden}` — that would clip anything a
     card is allowed to overflow, and an overflow context on a
     calendar ancestor collapses FullCalendar's month grid outright
     (see the standing warning in pbc-calendar.css).
   · not the table — `.pbc-table-wrap` owns `overflow-x:auto` for
     wide tables, and rounding individual corner cells would need a
     selector per table type, per corner, per first/last row.
   · the flush body clips ONE box and covers tables, datatables and
     `.pbc-row` lists alike.

   The radius is applied per EDGE, not per box: only the corners
   that actually touch the card's own edge are rounded, so a flush
   body sitting under a `.pbc-card__head` (or above a `__foot`,
   which rounds its own end corners already) keeps its interior
   corners square — which is correct there.

   ✅ Safe with the row-actions menu: `.pbc-rowacts__menu` is
   `position:fixed`, laid out against the viewport, so no ancestor's
   overflow can clip it — that is exactly why it was made fixed
   (K-4.11 add. 1). Verified: no flush body contains a sticky header
   or a Bootstrap dropdown.
   ========================================================== */
.pbc-card__body--flush{padding:0;overflow:hidden}
.pbc-card > .pbc-card__body--flush:first-child{
  border-start-start-radius:var(--pbc-radius-card);
  border-start-end-radius:var(--pbc-radius-card);
}
.pbc-card > .pbc-card__body--flush:last-child{
  border-end-start-radius:var(--pbc-radius-card);
  border-end-end-radius:var(--pbc-radius-card);
}
.pbc-spacer{margin-inline-start:auto}

/* ==========================================================
   PAGE HEADER + BREADCRUMB
   ========================================================== */
/* .pbc-crumb / .pbc-crumb__sep were deleted with the breadcrumbs themselves
   (§K K-4.14, owner 2026-08-02: "remove all breadcrumbs on all pages"). The
   markup is gone from all 81 blades, so the component had zero consumers. */
.pbc-pagehead{display:flex;align-items:flex-start;gap:var(--pbc-space-4);margin-bottom:var(--pbc-section-gap)}
.pbc-pagehead__title{font-family:var(--pbc-font-heading);font-weight:var(--pbc-weight-heading);font-size:var(--pbc-text-2xl);color:var(--pbc-ink-heading);letter-spacing:var(--pbc-tracking-tight);line-height:var(--pbc-leading-tight)}
.pbc-pagehead__sub{font-size:var(--pbc-text-base);color:var(--pbc-ink-muted);margin-top:var(--pbc-space-1)}

/* ==========================================================
   LIST ROWS — the airy two-line pattern
   ========================================================== */
.pbc-list{display:flex;flex-direction:column}
.pbc-row{
  display:flex;align-items:center;gap:var(--pbc-space-3);
  padding-block:var(--pbc-row-pad-y);
  padding-inline:var(--pbc-space-4);
  border-bottom:var(--pbc-border-width) solid var(--pbc-border-subtle);
  text-decoration:none;color:inherit;
  transition:background-color var(--pbc-transition);
}
.pbc-row:last-child{border-bottom:none}
.pbc-row:hover{background:var(--pbc-surface-hover)}
.pbc-row.is-selected{background:var(--pbc-surface-active)}
.pbc-row:focus-visible{outline:none;box-shadow:var(--pbc-focus-ring);border-radius:var(--pbc-radius-sm)}
/* ⚠⚠ THE `display:block` ON THE NEXT TWO IS LOAD-BEARING — DO NOT REMOVE IT.
   Both were inline, so in any consumer that renders them as <span> (or inside a
   table cell) the title ran straight into its own sub-line — "Priya NairClaims" —
   and `margin-top` was inert because margins do nothing on an inline box.
   This is the FOURTH sighting of the same defect class in the component layer:
   `.pbc-notif__t/__m/__when` (K-4.OVERLAYS), `.pbc-step__title/__desc` (K-4.9),
   `.pbc-ccase__s` (K-4.24, worked around per-screen), and this one — found again
   while building the P-7 picker rows (§14.295). Every static check passed all four
   times; it is only ever caught by LOOKING. Fixed at the definition here so the
   fifth consumer does not have to work around it. §14.297 / K-4.29. */
.pbc-row__main{min-width:0;flex:1}
.pbc-row__title{display:block;font-size:var(--pbc-text-base);font-weight:var(--pbc-weight-semibold);color:var(--pbc-ink-heading);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pbc-row__sub{display:block;font-size:var(--pbc-text-sm);color:var(--pbc-ink-muted);margin-top:var(--pbc-space-0-5)}

/* group header inside a list (status-grouped case list) */
.pbc-group{
  display:flex;align-items:center;gap:var(--pbc-space-2);
  padding-block:var(--pbc-space-2-5);
  padding-inline:var(--pbc-space-4);
  background:var(--pbc-surface-soft);
  border-bottom:var(--pbc-border-width) solid var(--pbc-border-subtle);
  font-size:var(--pbc-text-sm);font-weight:var(--pbc-weight-semibold);
  color:var(--pbc-ink-muted);
}

/* ==========================================================
   FILTER BAR — chips with live counts
   ========================================================== */
.pbc-filterbar{
  display:flex;align-items:center;gap:var(--pbc-space-1);flex-wrap:wrap;
  padding:var(--pbc-space-2);
  background:var(--pbc-surface-soft);
  border:var(--pbc-border-width) solid var(--pbc-border);
  border-radius:var(--pbc-radius-btn);
}
.pbc-chip{
  display:inline-flex;align-items:center;gap:var(--pbc-space-2);
  height:var(--pbc-control-h-sm);
  padding-inline:var(--pbc-space-3);
  border-radius:var(--pbc-radius-sm);
  border:var(--pbc-border-width) solid transparent;
  background:transparent;color:var(--pbc-ink-muted);
  font-family:inherit;font-size:var(--pbc-text-sm);font-weight:var(--pbc-weight-semibold);
  cursor:pointer;white-space:nowrap;
  transition:background-color var(--pbc-transition),color var(--pbc-transition);
}
.pbc-chip:hover{background:var(--pbc-surface);color:var(--pbc-ink-heading)}
.pbc-chip.is-active{background:var(--pbc-surface);color:var(--pbc-ink-heading);border-color:var(--pbc-border);box-shadow:var(--pbc-shadow-xs)}
.pbc-chip:focus-visible{outline:none;box-shadow:var(--pbc-focus-ring)}

/* ==========================================================
   TABS
   ========================================================== */
.pbc-tabs{display:flex;align-items:center;gap:var(--pbc-space-6);border-bottom:var(--pbc-border-width) solid var(--pbc-border)}
.pbc-tab{
  display:inline-flex;align-items:center;gap:var(--pbc-space-2);
  padding-block:var(--pbc-space-3);
  border:none;background:none;cursor:pointer;
  font-family:inherit;font-size:var(--pbc-text-base);font-weight:var(--pbc-weight-medium);
  color:var(--pbc-ink-muted);
  border-bottom:2px solid transparent;
  margin-bottom:-1px;
  transition:color var(--pbc-transition),border-color var(--pbc-transition);
}
.pbc-tab:hover{color:var(--pbc-ink-heading)}
.pbc-tab.is-active{color:var(--pbc-brand-accent);border-bottom-color:var(--pbc-brand-accent);font-weight:var(--pbc-weight-semibold)}
.pbc-tab:focus-visible{outline:none;box-shadow:var(--pbc-focus-ring);border-radius:var(--pbc-radius-xs)}

/* ==========================================================
   PHASE BAR — chevron progression (the case detail centrepiece)
   ========================================================== */
.pbc-phases{display:flex;align-items:stretch;gap:var(--pbc-space-1);overflow-x:auto}
.pbc-phase{
  /* min-width is deliberately small: a workflow can have 6–8 phases, and
     with the larger type a fixed 120px min forced the whole bar to scroll
     on a 1280px screen. Long phase names ellipsis instead; the current
     phase is allowed to grow so it always reads in full. */
  flex:1 1 0;min-width:84px;
  display:flex;align-items:center;justify-content:center;gap:var(--pbc-space-2);
  padding-block:var(--pbc-space-2-5);
  padding-inline:var(--pbc-space-4);
  background:var(--pbc-neutral-100);
  color:var(--pbc-ink-muted);
  font-size:var(--pbc-text-sm);font-weight:var(--pbc-weight-semibold);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  clip-path:polygon(0 0,calc(100% - 12px) 0,100% 50%,calc(100% - 12px) 100%,0 100%,12px 50%);
}
.pbc-phase.is-current{flex-grow:1.6}
[dir="rtl"] .pbc-phase{clip-path:polygon(12px 0,100% 0,calc(100% - 12px) 50%,100% 100%,12px 100%,0 50%)}
.pbc-phase:first-child{clip-path:polygon(0 0,calc(100% - 12px) 0,100% 50%,calc(100% - 12px) 100%,0 100%)}
[dir="rtl"] .pbc-phase:first-child{clip-path:polygon(0 0,100% 0,calc(100% - 12px) 50%,100% 100%,0 100%)}
.pbc-phase.is-done{background:var(--pbc-success-100);color:var(--pbc-success-600)}
.pbc-phase.is-current{background:var(--pbc-brand-600);color:var(--pbc-ink-on-brand)}

/* ==========================================================
   STEPPER — vertical checklist (setup wizard)
   ========================================================== */
.pbc-steps{display:flex;flex-direction:column}
.pbc-step{display:flex;gap:var(--pbc-space-3);padding-block:var(--pbc-space-3);position:relative}
.pbc-step__marker{
  width:22px;height:22px;flex:none;border-radius:var(--pbc-radius-pill);
  border:2px solid var(--pbc-border-strong);background:var(--pbc-surface);
  display:grid;place-content:center;
  font-size:var(--pbc-text-xs);font-weight:var(--pbc-weight-bold);color:var(--pbc-ink-faint);
}
.pbc-step__rail{
  position:absolute;inset-inline-start:10px;top:34px;bottom:-4px;
  width:2px;background:var(--pbc-border);
}
.pbc-step:last-child .pbc-step__rail{display:none}
/* ⚠ display:block is LOAD-BEARING (§K K-4.9, 2026-08-02). Both are rendered as
   <span>s; while they were inline the title and its description ran onto ONE
   line ("Starting pointCloned a template") and the desc's margin-top was inert.
   Same defect class as .pbc-notif__t/__m/__when in K-4.OVERLAYS. Latent since
   K-2 — the component had no consumer in the app, so it was never seen. */
.pbc-step__title{display:block;font-size:var(--pbc-text-base);font-weight:var(--pbc-weight-semibold);color:var(--pbc-ink-heading)}
.pbc-step__desc{display:block;font-size:var(--pbc-text-sm);color:var(--pbc-ink-muted);margin-top:var(--pbc-space-0-5)}
.pbc-step.is-done .pbc-step__marker{background:var(--pbc-success-500);border-color:var(--pbc-success-500);color:var(--pbc-ink-on-brand)}
.pbc-step.is-done .pbc-step__rail{background:var(--pbc-success-500)}
/* ⚠ NO STRIKETHROUGH ON A COMPLETED STEP — owner's decision 2026-08-02, do not
   re-add. A struck-out title reads as "cancelled"; a wizard step you can still
   go back and edit is finished, not withdrawn. The green marker carries "done". */
.pbc-step.is-done .pbc-step__title{color:var(--pbc-ink-muted)}
.pbc-step.is-current .pbc-step__marker{border-color:var(--pbc-brand-accent);color:var(--pbc-brand-accent)}
.pbc-step.is-locked{opacity:.55}

/* ==========================================================
   WIZARD TRACKER — the horizontal sibling of .pbc-steps
   §K K-4.9 (2026-08-02). Owner picked option D from
   PBC Mockup/setup-wizard-options.html: markers spread across
   the full width, labels centred underneath, the connecting
   rail filling in behind you.

   ⚠ It is a SEPARATE component from .pbc-steps on purpose.
   .pbc-steps is vertical and carries a per-step description;
   this one is horizontal and label-only. Do not try to make
   one serve both — that is how the portal's .pbc-step ended
   up clashing with this file's in the first place.

   RTL: the rail uses logical inset properties, so it reverses
   with the document. There is no separate RTL rule and there
   must not be one.
   ========================================================== */
.pbc-wizbar{display:flex;align-items:flex-start;gap:var(--pbc-space-1)}
.pbc-wizbar__step{
  flex:1 1 0;min-width:0;position:relative;
  display:flex;flex-direction:column;align-items:center;
  gap:var(--pbc-space-2);text-align:center;
}
/* The rail is drawn from this step's marker toward the NEXT one. Because every
   step is flex:1 1 0 they are equal width, so reaching -50% + 20px lands
   exactly on the next marker's edge. */
.pbc-wizbar__step::after{
  content:"";position:absolute;top:14px;height:2px;
  inset-inline-start:calc(50% + 20px);
  inset-inline-end:calc(-50% + 20px);
  background:var(--pbc-border);
}
.pbc-wizbar__step:last-child::after{display:none}
.pbc-wizbar__marker{
  width:30px;height:30px;flex:none;
  border-radius:var(--pbc-radius-pill);
  border:2px solid var(--pbc-border-strong);
  background:var(--pbc-surface);
  display:grid;place-content:center;
  font-size:var(--pbc-text-sm);font-weight:var(--pbc-weight-bold);
  color:var(--pbc-ink-faint);
}
.pbc-wizbar__label{
  font-size:var(--pbc-text-sm);font-weight:var(--pbc-weight-medium);
  color:var(--pbc-ink-muted);line-height:var(--pbc-leading-snug);
}
/* ⚠⚠ THE FILL IS success-500 AND MUST STAY. Measured 2026-08-02, all four ways:
   success-500 #2F8F6B → white glyph 3.99:1, marker-vs-card 3.99:1 light /
   3.70:1 dark — clears the 3:1 non-text bar everywhere (the glyph is an icon,
   aria-hidden; the step's state is carried by aria-current + the label).
   Darkening it to fix the glyph BREAKS DARK MODE: #256F53 gives a 6.04:1 glyph
   but the marker then sits at 2.45:1 on the dark card and disappears.
   And `--pbc-success-600` is NOT an option — it FLIPS to #7FD3B2 in dark
   (an ink colour), so as a fill it prints a pastel mint tick. Same trap as
   --pbc-call-accept in K-4.OVERLAYS. success-500 does not flip. Leave it. */
.pbc-wizbar__step.is-done .pbc-wizbar__marker{
  background:var(--pbc-success-500);border-color:var(--pbc-success-500);
  color:var(--pbc-ink-on-brand);
}
.pbc-wizbar__step.is-done::after{background:var(--pbc-success-500)}
.pbc-wizbar__step.is-done .pbc-wizbar__label{color:var(--pbc-ink-body)}
/* Solid brand-600 fill, never steel — a steel fill under white ink is 3.91:1. */
.pbc-wizbar__step.is-current .pbc-wizbar__marker{
  background:var(--pbc-brand-600);border-color:var(--pbc-brand-600);
  color:var(--pbc-ink-on-brand);
}
.pbc-wizbar__step.is-current .pbc-wizbar__label{
  color:var(--pbc-ink-heading);font-weight:var(--pbc-weight-semibold);
}
/* Narrow: the markers and rail still tell the story, so only the step you are
   on keeps its label. Five labels below ~640px wrap into an unreadable stack. */
@media (max-width:640px){
  .pbc-wizbar__label{display:none}
  .pbc-wizbar__step.is-current .pbc-wizbar__label{display:block}
}

/* ----------------------------------------------------------
   CHOICE TILES — a grid of "pick one of these" cards.
   §K K-4.9. Built for wizard Step 1 (pick a template), and
   deliberately generic: the organisation wizard has the same
   shape. NOT Bootstrap's .row/.col — those bring a 12-column
   gutter system that fights the token rhythm (trap 3).
   A tile is a flat bordered surface, not a nested .pbc-card,
   so it does not stack a second shadow inside a card body.
   ---------------------------------------------------------- */
.pbc-optgrid{
  display:grid;
  grid-template-columns:repeat(auto-fill,minmax(240px,1fr));
  gap:var(--pbc-space-4);
}
.pbc-optcard{
  display:flex;flex-direction:column;gap:var(--pbc-space-2);
  padding:var(--pbc-space-4);
  background:var(--pbc-surface);
  border:var(--pbc-border-width) solid var(--pbc-border);
  border-radius:var(--pbc-radius-chip);
  transition:border-color var(--pbc-transition);
}
.pbc-optcard:hover{border-color:var(--pbc-border-strong)}
.pbc-optcard__title{
  font-size:var(--pbc-text-base);font-weight:var(--pbc-weight-semibold);
  color:var(--pbc-ink-heading);
}
.pbc-optcard__desc{
  font-size:var(--pbc-text-sm);color:var(--pbc-ink-muted);
  line-height:var(--pbc-leading-snug);
}
/* margin-top:auto pins the actions to the bottom so tiles of different text
   lengths still line their buttons up. Block axis — unrelated to the inline
   auto-margin trap in §14.265. */
.pbc-optcard__foot{
  display:flex;gap:var(--pbc-space-2);flex-wrap:wrap;
  margin-top:auto;padding-top:var(--pbc-space-2);
}

/* ----------------------------------------------------------
   INSET PANEL — a well nested INSIDE a card, for a drawer or
   a settings sub-form. §K K-4.12, built for the field
   builder's per-field settings drawer.
   Deliberately NOT a nested .pbc-card: a card inside a card
   inside a table cell stacks a second shadow and a second
   border radius, which reads as clutter. A sunken well says
   "this belongs to the row above it".
   ---------------------------------------------------------- */
.pbc-inset{
  display:flex;flex-direction:column;gap:var(--pbc-space-2);
  padding:var(--pbc-space-4);
  background:var(--pbc-surface-sunken);
  border:var(--pbc-border-width) solid var(--pbc-border-subtle);
  border-radius:var(--pbc-radius-chip);
}

/* ==========================================================
   CRITERION ROW — one line of "what is still needed"
   ----------------------------------------------------------
   §K K-4.26 (§14.294). Ported from the approved gallery
   specimen (`enduser-case-detail-options.html`, decision 4-A)
   rather than re-derived. One row = a state icon + a sentence,
   used inside `.pbc-inset` under the phase bar on the case page.
   ⚠ NOT `.pbc-check` — that is a real checkbox the user can
   click. These are read-only facts the workflow engine decided;
   making them look clickable would invite people to try.
   ⚠ `display:flex` with `align-items:flex-start` so a wrapping
   sentence keeps its icon on the first line rather than centring
   it against a two-line block.
   ========================================================== */
.pbc-crit{
  display:flex;align-items:flex-start;gap:var(--pbc-space-2-5);
  font-size:var(--pbc-text-base);
  color:var(--pbc-ink-body);
}
.pbc-crit > i{
  color:var(--pbc-ink-faint);
  margin-block-start:3px;      /* optical: line the glyph up with the cap height */
  flex:none;
}
/* Done reads as "already handled": the tick carries the colour, the words go
   quiet. No strikethrough — the owner ruled that out for wizard steps (§K
   K-4.9) and the reasoning is the same here: finished is not cancelled. */
.pbc-crit.is-done{color:var(--pbc-ink-muted)}
.pbc-crit.is-done > i{color:var(--pbc-success-600)}

/* ==========================================================
   ACTIVITY TIMELINE — case history
   ========================================================== */
.pbc-timeline{display:flex;flex-direction:column;gap:var(--pbc-space-2)}
.pbc-timeline__date{
  align-self:flex-start;
  padding-block:var(--pbc-space-1);padding-inline:var(--pbc-space-3);
  border-radius:var(--pbc-radius-pill);
  background:var(--pbc-neutral-100);color:var(--pbc-ink-muted);
  font-size:var(--pbc-text-sm);font-weight:var(--pbc-weight-semibold);
  margin-block:var(--pbc-space-3) var(--pbc-space-1);
}
.pbc-event{
  display:flex;align-items:flex-start;gap:var(--pbc-space-3);
  padding:var(--pbc-space-3) var(--pbc-space-4);
  background:var(--pbc-surface);
  border:var(--pbc-border-width) solid var(--pbc-border-subtle);
  border-radius:var(--pbc-radius-chip);
}
.pbc-event__text{flex:1;font-size:var(--pbc-text-base);color:var(--pbc-ink-body);line-height:var(--pbc-leading-snug)}
.pbc-event__actor{font-weight:var(--pbc-weight-semibold);color:var(--pbc-ink-heading)}
.pbc-event__time{font-size:var(--pbc-text-sm);color:var(--pbc-ink-faint);white-space:nowrap}

/* ==========================================================
   MODAL
   ========================================================== */
.pbc-scrim{position:fixed;inset:0;background:var(--pbc-overlay);z-index:var(--pbc-z-overlay)}
.pbc-modal{
  width:100%;max-width:var(--pbc-modal-w);
  background:var(--pbc-surface);
  border-radius:var(--pbc-radius-modal);
  box-shadow:var(--pbc-shadow-lg);
  overflow:hidden;
}
.pbc-modal--sm{max-width:var(--pbc-modal-w-sm)}
.pbc-modal--lg{max-width:var(--pbc-modal-w-lg)}
.pbc-modal__head{display:flex;align-items:flex-start;gap:var(--pbc-space-3);padding:var(--pbc-card-pad)}
.pbc-modal__icon{
  width:44px;height:44px;flex:none;border-radius:var(--pbc-radius-chip);
  background:var(--pbc-brand-100);color:var(--pbc-brand-accent);
  display:grid;place-content:center;
}
.pbc-modal__icon--danger{background:var(--pbc-danger-100);color:var(--pbc-danger-600)}
.pbc-modal__title{font-size:var(--pbc-text-lg);font-weight:var(--pbc-weight-semibold);color:var(--pbc-ink-heading)}
.pbc-modal__sub{font-size:var(--pbc-text-sm);color:var(--pbc-ink-muted);margin-top:var(--pbc-space-1)}
.pbc-modal__body{padding-inline:var(--pbc-card-pad);padding-bottom:var(--pbc-space-5)}
.pbc-modal__foot{
  display:flex;align-items:center;justify-content:flex-end;gap:var(--pbc-space-3);
  padding:var(--pbc-space-4) var(--pbc-card-pad);
  border-top:var(--pbc-border-width) solid var(--pbc-border-subtle);
  background:var(--pbc-surface-soft);
}

/* ==========================================================
   INLINE ALERT / TOAST
   ========================================================== */
.pbc-alert{
  display:flex;align-items:flex-start;gap:var(--pbc-space-3);
  padding:var(--pbc-space-3) var(--pbc-space-4);
  border-radius:var(--pbc-radius-chip);
  border:var(--pbc-border-width) solid transparent;
  font-size:var(--pbc-text-base);
  border-inline-start-width:3px;
}
.pbc-alert__title{font-weight:var(--pbc-weight-semibold);display:block}
.pbc-alert--info   {background:var(--pbc-info-100);   color:var(--pbc-info-600);   border-color:var(--pbc-info-border)}
.pbc-alert--success{background:var(--pbc-success-100);color:var(--pbc-success-600);border-color:var(--pbc-success-border)}
.pbc-alert--warning{background:var(--pbc-warning-100);color:var(--pbc-warning-600);border-color:var(--pbc-warning-border)}
.pbc-alert--danger {background:var(--pbc-danger-100); color:var(--pbc-danger-600); border-color:var(--pbc-danger-border)}
.pbc-toast{
  display:flex;align-items:center;gap:var(--pbc-space-3);
  padding:var(--pbc-space-3) var(--pbc-space-4);
  background:var(--pbc-surface);
  border:var(--pbc-border-width) solid var(--pbc-border);
  border-radius:var(--pbc-radius-chip);
  box-shadow:var(--pbc-shadow-popover);
  max-width:420px;
}

/* ==========================================================
   EMPTY STATE
   ========================================================== */
.pbc-empty{
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  text-align:center;
  padding:var(--pbc-space-16) var(--pbc-space-6);
  gap:var(--pbc-space-2);
}
.pbc-empty__icon{
  width:52px;height:52px;border-radius:var(--pbc-radius-chip);
  background:var(--pbc-neutral-100);color:var(--pbc-ink-faint);
  display:grid;place-content:center;margin-bottom:var(--pbc-space-2);
}
.pbc-empty__title{font-size:var(--pbc-text-lg);font-weight:var(--pbc-weight-semibold);color:var(--pbc-ink-heading)}
.pbc-empty__text{font-size:var(--pbc-text-base);color:var(--pbc-ink-muted);max-width:38ch}
.pbc-empty__actions{display:flex;gap:var(--pbc-space-3);margin-top:var(--pbc-space-4)}

/* ==========================================================
   LOADING — skeletons + spinner
   ========================================================== */
.pbc-skeleton{
  background:linear-gradient(90deg,
    var(--pbc-neutral-100) 25%,
    var(--pbc-surface-sunken) 37%,
    var(--pbc-neutral-100) 63%);
  background-size:400% 100%;
  border-radius:var(--pbc-radius-xs);
  animation:pbc-shimmer 1.4s ease infinite;
}
@keyframes pbc-shimmer{0%{background-position:100% 50%}100%{background-position:0 50%}}
.pbc-skeleton--text{height:12px;margin-block:var(--pbc-space-1)}
.pbc-skeleton--title{height:16px;width:40%}
.pbc-skeleton--circle{border-radius:var(--pbc-radius-pill)}
.pbc-spinner{
  width:20px;height:20px;flex:none;
  border:2px solid var(--pbc-border-strong);border-top-color:var(--pbc-brand-accent);
  border-radius:var(--pbc-radius-pill);
  animation:pbc-spin var(--pbc-duration-slow) linear infinite;
}
@media (prefers-reduced-motion:reduce){
  .pbc-skeleton,.pbc-spinner,.pbc-btn.is-loading::before{animation:none}
}

/* ==========================================================
   PROGRESS
   ========================================================== */
.pbc-progress{height:6px;background:var(--pbc-neutral-100);border-radius:var(--pbc-radius-pill);overflow:hidden}
.pbc-progress__bar{height:100%;background:var(--pbc-brand-accent);border-radius:var(--pbc-radius-pill);transition:width var(--pbc-duration-base) var(--pbc-ease-out)}
.pbc-progress__bar--success{background:var(--pbc-success-500)}

/* ==========================================================
   DROPDOWN MENU
   ========================================================== */
.pbc-menu{
  min-width:200px;padding:var(--pbc-space-1-5);
  background:var(--pbc-surface);
  border:var(--pbc-border-width) solid var(--pbc-border);
  border-radius:var(--pbc-radius-chip);
  box-shadow:var(--pbc-shadow-popover);
}
.pbc-menu__item{
  display:flex;align-items:center;gap:var(--pbc-space-2-5);width:100%;
  padding-block:var(--pbc-space-2);padding-inline:var(--pbc-space-3);
  border:none;background:none;cursor:pointer;text-align:start;
  border-radius:var(--pbc-radius-sm);
  font-family:inherit;font-size:var(--pbc-text-base);color:var(--pbc-ink-body);
}
.pbc-menu__item:hover{background:var(--pbc-surface-hover);color:var(--pbc-ink-heading)}
.pbc-menu__item:focus-visible{outline:none;box-shadow:var(--pbc-focus-ring)}
.pbc-menu__item--danger{color:var(--pbc-danger-600)}
.pbc-menu__sep{height:1px;background:var(--pbc-border-subtle);margin-block:var(--pbc-space-1-5)}

/* ==========================================================
   SIDEBAR NAV
   ========================================================== */
.pbc-sidebar{
  width:var(--pbc-sidebar-w);flex:none;
  background:var(--pbc-sidebar-bg);
  border-inline-end:var(--pbc-border-width) solid var(--pbc-sidebar-border);
  padding:var(--pbc-space-4);
  display:flex;flex-direction:column;
}
.pbc-nav__group{
  font-size:var(--pbc-text-xs);font-weight:var(--pbc-weight-bold);
  letter-spacing:var(--pbc-tracking-caps);text-transform:uppercase;
  /* No opacity here: at .8 this 11.5px uppercase label dropped to
     4.21:1 against the top of the sidebar gradient. Full strength = 5.64:1. */
  color:var(--pbc-brand-300);
  padding-block:var(--pbc-space-2);padding-inline:var(--pbc-space-3);
  margin-top:var(--pbc-space-3);
}
.pbc-nav__item{
  display:flex;align-items:center;gap:var(--pbc-space-3);
  padding-block:var(--pbc-space-2-5);padding-inline:var(--pbc-space-3);
  border-radius:var(--pbc-radius-sm);
  color:var(--pbc-sidebar-ink);
  font-size:var(--pbc-text-base);font-weight:var(--pbc-weight-medium);
  text-decoration:none;cursor:pointer;
  margin-bottom:var(--pbc-space-1);
  transition:background-color var(--pbc-transition),color var(--pbc-transition);
}
.pbc-nav__item:hover{background:var(--pbc-sidebar-hover);color:var(--pbc-sidebar-ink-strong)}
.pbc-nav__item.is-active{background:var(--pbc-sidebar-active);color:var(--pbc-sidebar-ink-strong);font-weight:var(--pbc-weight-semibold);position:relative}
/* §K A3 / NV-1 D (§14.336) — the edge bar. See the twin rule on
   `#sidebar-nav .nav-link:not(.collapsed)` further down THIS FILE: both are
   consumers of the same design and must always be changed together, or the
   design-system nav and the live shell nav drift apart. */
.pbc-nav__item.is-active::before{content:"";position:absolute;inset-inline-start:0;top:6px;bottom:6px;width:3px;border-radius:0 2px 2px 0;background:var(--pbc-brand-300)}
.pbc-nav__item:focus-visible{outline:none;box-shadow:var(--pbc-focus-ring)}
.pbc-nav__badge{margin-inline-start:auto}

/* ==========================================================
   PERMISSION MATRIX
   ========================================================== */
.pbc-matrix{width:100%;border-collapse:collapse}
.pbc-matrix th{
  text-align:start;
  padding-block:var(--pbc-space-3);padding-inline:var(--pbc-space-4);
  font-size:var(--pbc-text-xs);font-weight:var(--pbc-weight-bold);
  letter-spacing:var(--pbc-tracking-caps);text-transform:uppercase;
  color:var(--pbc-ink-muted);
  border-bottom:var(--pbc-border-width) solid var(--pbc-border);
}
.pbc-matrix th:not(:first-child),.pbc-matrix td:not(:first-child){
  text-align:center;width:var(--pbc-matrix-col);
}
.pbc-matrix td{
  padding-block:var(--pbc-cell-pad-y);padding-inline:var(--pbc-space-4);
  border-bottom:var(--pbc-border-width) solid var(--pbc-border-subtle);
  font-size:var(--pbc-text-base);color:var(--pbc-ink-body);
}
.pbc-matrix tbody tr:hover{background:var(--pbc-surface-hover)}
.pbc-matrix__section td{
  font-size:var(--pbc-text-sm);font-weight:var(--pbc-weight-bold);
  letter-spacing:var(--pbc-tracking-caps);text-transform:uppercase;
  color:var(--pbc-ink-heading);background:var(--pbc-surface-soft);
  padding-block:var(--pbc-space-2-5);
}
.pbc-matrix__section:hover td{background:var(--pbc-surface-soft)}
/* the matrix is the densest screen in the app — give its ticks
   a bigger hit area than the default checkbox */
.pbc-matrix td input[type="checkbox"]{width:22px;height:22px}


/* ==========================================================
   AUTH SHELL — the signed-out screens (login first, K-4)
   ----------------------------------------------------------
   OWNER DIRECTION 2026-07-25 (revision 2, replaced the split
   layout): ONE page, the WHOLE page blue, everything in a
   single centred column — logo, then PBC, then the slogan,
   then the form directly underneath.

   ⚠ THE FORM SITS ON THE BRAND, NOT ON WHITE. That inverts
   every ink decision, so the rules below are load-bearing:
     - gradient is --pbc-brand-gradient-deep. The plain
       --pbc-brand-gradient ends in steel and white on steel
       is 3.91:1.
     - all copy uses --pbc-sidebar-ink-strong, which holds
       5.9:1 even on the lightest stop. --pbc-sidebar-ink
       measures 3.26:1 there and must NOT be used.
     - the INPUTS stay light with dark ink on purpose. A
       translucent dark input looks better but Safari's
       autofill forces its own light background and keeps the
       author's text colour, so autofilled credentials render
       white-on-white — invisible. The owner uses Safari with
       a password manager. Legibility beats the darker look.
     - the button is therefore INVERSE (light fill, navy ink):
       a brand-600 button would be nearly invisible against
       the lower half of the gradient (2.5:1 edge).

   Logical properties throughout, so it mirrors under RTL.
   NOTE: guests are always served English today (SetLocale
   localizes authenticated users only), so RTL here is
   future-proofing, not a live path.
   ========================================================== */
.pbc-auth{
  min-height:100vh;
  display:flex;
  align-items:center;
  justify-content:center;
  padding:var(--pbc-space-12) var(--pbc-space-5);
  background:var(--pbc-brand-gradient-deep);
}

/* the single centred column */
.pbc-auth__box{
  width:100%;
  max-width:400px;
  display:flex;
  flex-direction:column;
  align-items:center;
  text-align:center;
}

/* --- brand stack: logo → name → slogan --- */
.pbc-auth__brand{
  display:flex;flex-direction:column;align-items:center;
  gap:var(--pbc-space-3);
  margin-bottom:var(--pbc-space-8);
}
.pbc-auth__logo{
  width:132px;height:132px;
  object-fit:contain;
}
/* an organisation without a logo gets its initials in the same footprint */
.pbc-auth__monogram{
  width:132px;height:132px;
  border-radius:var(--pbc-radius-pill);
  background:var(--pbc-on-brand-fill);
  border:var(--pbc-border-width) solid var(--pbc-on-brand-border);
  display:grid;place-items:center;
  font-family:var(--pbc-font-heading);
  font-weight:var(--pbc-weight-heading);
  font-size:var(--pbc-text-3xl);
  color:var(--pbc-sidebar-ink-strong);
  overflow:hidden;
}
.pbc-auth__monogram img{width:100%;height:100%;object-fit:cover;background:var(--pbc-surface)}
.pbc-auth__wordmark{
  font-family:var(--pbc-font-heading);
  font-weight:var(--pbc-weight-heading);
  font-size:var(--pbc-text-3xl);
  letter-spacing:var(--pbc-tracking-tight);
  line-height:var(--pbc-leading-tight);
  color:var(--pbc-sidebar-ink-strong);
}
.pbc-auth__tagline{
  font-size:var(--pbc-text-md);
  line-height:var(--pbc-leading-relaxed);
  color:var(--pbc-sidebar-ink-strong);
  max-width:32ch;
  margin:0;
}
.pbc-auth__brandfoot{
  font-size:var(--pbc-text-xs);
  letter-spacing:var(--pbc-tracking-caps);
  text-transform:uppercase;
  color:var(--pbc-sidebar-ink-strong);
}

/* --- the form, directly under the brand stack --- */
.pbc-auth__fields{
  width:100%;
  display:flex;flex-direction:column;
  gap:var(--pbc-space-5);
  text-align:start;
}
/* labels are ON the brand here, so they invert */
.pbc-auth .pbc-field__label{color:var(--pbc-sidebar-ink-strong)}
.pbc-auth__row{
  display:flex;align-items:center;justify-content:space-between;
  gap:var(--pbc-space-4);flex-wrap:wrap;
}
.pbc-auth .pbc-check{color:var(--pbc-sidebar-ink-strong)}
.pbc-auth__link{
  font-size:var(--pbc-text-sm);
  font-weight:var(--pbc-weight-semibold);
  color:var(--pbc-sidebar-ink-strong);
  text-decoration:underline;
  border-radius:var(--pbc-radius-xs);
}
.pbc-auth__link:hover{color:var(--pbc-sidebar-ink-strong);text-decoration:none}
.pbc-auth__link:focus-visible{outline:none;box-shadow:var(--pbc-focus-ring)}
.pbc-auth__foot{
  margin-top:var(--pbc-space-10);
  font-size:var(--pbc-text-xs);
  letter-spacing:var(--pbc-tracking-caps);
  text-transform:uppercase;
  color:var(--pbc-sidebar-ink-strong);
}
.pbc-auth__foot b{font-weight:var(--pbc-weight-bold)}

/* alerts keep their own light surfaces — they must read as notices,
   and they already pass AA on their own tints */
.pbc-auth .pbc-alert{width:100%;margin-bottom:var(--pbc-space-5);text-align:start}

/* --- small screens --- */
@media (max-width:600px){
  .pbc-auth{padding:var(--pbc-space-8) var(--pbc-space-4);min-height:100dvh}
  .pbc-auth__logo,.pbc-auth__monogram{width:96px;height:96px}
  .pbc-auth__monogram{font-size:var(--pbc-text-2xl)}
  .pbc-auth__wordmark{font-size:var(--pbc-text-2xl)}
  .pbc-auth__brand{margin-bottom:var(--pbc-space-6)}
}

/* ==========================================================
   INVERSE BUTTON — for solid brand/navy backgrounds
   A primary (brand-600) button on the login page would sit at
   ~2.5:1 against the gradient behind it and read as a flat
   patch. The inverse is a light fill with brand ink: 18:1
   against the page, 8.6:1 for its own label.
   ========================================================== */
.pbc-btn--inverse{
  background:var(--pbc-surface);
  color:var(--pbc-brand-700);
  box-shadow:var(--pbc-shadow-sm);
}
.pbc-btn--inverse:hover{background:var(--pbc-brand-100);color:var(--pbc-brand-800)}

/* ==========================================================
   AUTH FOOTER ROW — terms · privacy · language
   ----------------------------------------------------------
   One row under the "Powered by PBC" credit (owner, K-4).

   The language picker is a <details>/<summary> disclosure, not
   a Bootstrap dropdown: the guest layout does NOT load
   Bootstrap, and this must not depend on JS at all. <details>
   is keyboard-accessible and closes on Escape natively.

   Everything here sits ON the brand gradient, so all ink is
   --pbc-sidebar-ink-strong (5.9:1 at the worst stop). The open
   list flips to a normal light surface so the language names
   read as a menu, not as more page furniture.
   ========================================================== */
.pbc-auth__meta{
  margin-top:var(--pbc-space-3);
  display:flex;align-items:center;justify-content:center;
  flex-wrap:wrap;
  gap:var(--pbc-space-2) var(--pbc-space-4);
  font-size:var(--pbc-text-xs);
}
.pbc-auth__meta a,
.pbc-auth__meta summary{
  color:var(--pbc-sidebar-ink-strong);
  text-decoration:none;
  cursor:pointer;
}
.pbc-auth__meta a:hover,
.pbc-auth__meta summary:hover{text-decoration:underline}
.pbc-auth__meta a:focus-visible,
.pbc-auth__meta summary:focus-visible{
  outline:none;box-shadow:var(--pbc-focus-ring);border-radius:var(--pbc-radius-xs);
}

/* --- language disclosure --- */
.pbc-langmenu{position:relative}
.pbc-langmenu > summary{
  list-style:none;
  display:inline-flex;align-items:center;gap:var(--pbc-space-1-5);
}
.pbc-langmenu > summary::-webkit-details-marker{display:none}
.pbc-langmenu > summary::after{
  content:'';
  width:0;height:0;
  border-inline-start:4px solid transparent;
  border-inline-end:4px solid transparent;
  border-top:5px solid currentColor;
  transition:transform var(--pbc-transition);
}
.pbc-langmenu[open] > summary::after{transform:rotate(180deg)}

.pbc-langmenu__list{
  position:absolute;
  bottom:calc(100% + var(--pbc-space-2));
  inset-inline-start:50%;
  transform:translateX(-50%);
  z-index:var(--pbc-z-dropdown);
  min-width:180px;
  background:var(--pbc-surface);
  border:var(--pbc-border-width) solid var(--pbc-border);
  border-radius:var(--pbc-radius-sm);
  box-shadow:var(--pbc-shadow-popover);
  padding:var(--pbc-space-1);
  display:flex;flex-direction:column;
  text-align:start;
}
[dir="rtl"] .pbc-langmenu__list{transform:translateX(50%)}

.pbc-langmenu__item{
  display:flex;align-items:center;justify-content:space-between;
  gap:var(--pbc-space-3);
  width:100%;
  padding:var(--pbc-space-2) var(--pbc-space-3);
  background:none;border:0;
  border-radius:var(--pbc-radius-xs);
  font-family:inherit;
  font-size:var(--pbc-text-sm);
  color:var(--pbc-ink-body);
  text-align:start;
  cursor:pointer;
}
.pbc-langmenu__item:hover{background:var(--pbc-surface-hover)}
.pbc-langmenu__item:focus-visible{outline:none;box-shadow:var(--pbc-focus-ring)}
.pbc-langmenu__item[aria-current="true"]{
  color:var(--pbc-brand-accent);
  font-weight:var(--pbc-weight-semibold);
  background:var(--pbc-surface-active);
}
/* the tick on the language already in use */
.pbc-langmenu__item[aria-current="true"]::after{content:'✓';font-size:var(--pbc-text-sm)}

/* explanatory paragraph on an auth screen (forgot-password's instructions).
   On the brand, so it takes the strong sidebar ink like everything else here. */
.pbc-auth__note{
  font-size:var(--pbc-text-sm);
  line-height:var(--pbc-leading-relaxed);
  color:var(--pbc-sidebar-ink-strong);
  margin:0 0 var(--pbc-space-6);
  text-align:start;
}

/* ==========================================================
   AUTH DOCUMENT — terms / privacy, rendered from markdown
   A readable light column on the brand page. The prose comes
   from markdown, so this is the ONE place the component layer
   styles bare elements — scoped inside .pbc-doc so it cannot
   reach Bootstrap or any app screen.
   ========================================================== */
.pbc-auth--doc{align-items:flex-start}
.pbc-auth__doc{
  width:100%;
  max-width:var(--pbc-modal-w-lg);
  background:var(--pbc-surface);
  border-radius:var(--pbc-radius-card);
  box-shadow:var(--pbc-shadow-lg);
  padding:var(--pbc-card-pad-lg);
  text-align:start;
  color:var(--pbc-ink-body);
}
.pbc-auth__doc h1,.pbc-auth__doc h2,.pbc-auth__doc h3{
  font-family:var(--pbc-font-heading);
  font-weight:var(--pbc-weight-heading);
  color:var(--pbc-ink-heading);
  letter-spacing:var(--pbc-tracking-tight);
  line-height:var(--pbc-leading-tight);
  margin:var(--pbc-space-8) 0 var(--pbc-space-3);
}
.pbc-auth__doc h1{font-size:var(--pbc-text-2xl);margin-top:0}
.pbc-auth__doc h2{font-size:var(--pbc-text-xl)}
.pbc-auth__doc h3{font-size:var(--pbc-text-lg)}
.pbc-auth__doc p,.pbc-auth__doc li{
  font-size:var(--pbc-text-md);
  line-height:var(--pbc-leading-relaxed);
  margin:0 0 var(--pbc-space-4);
}
.pbc-auth__doc ul,.pbc-auth__doc ol{padding-inline-start:var(--pbc-space-6);margin:0 0 var(--pbc-space-4)}
.pbc-auth__doc a{color:var(--pbc-brand-accent)}
.pbc-auth__doc strong{color:var(--pbc-ink-heading);font-weight:var(--pbc-weight-semibold)}
.pbc-auth__doc hr{border:0;border-top:var(--pbc-border-width) solid var(--pbc-border);margin:var(--pbc-space-8) 0}

/* ==========================================================
   STAT TILE — a headline number that drills into a filtered list
   ----------------------------------------------------------
   Added K-4 (2026-07-25) for the dashboard; the gallery had no
   stat pattern because it hadn't come up when K-2 was built.

   The number leads, the label follows underneath — the reverse
   of the old dashboard, where a coloured icon chip competed
   with the figure for attention. Colour appears ONLY when a
   number means something is wrong (--alert), never decoratively.
   ========================================================== */
.pbc-stats{
  display:grid;
  grid-template-columns:repeat(auto-fit,minmax(150px,1fr));
  gap:var(--pbc-space-6);
  /* Owner, 2026-07-25: "the spacing between the boxes and what's underneath is
     way too low". There was literally ZERO gap here — .pbc-stats and the content
     below it were siblings with no margin between them. */
  margin-block-end:var(--pbc-space-8);
}
/* COMPACT ROW — owner, 2026-08-08 (§K K-4.31): "the four boxes … are too wide, they
   have too much blank space in them right now. Make them a little bit more narrow,
   but keep them all centred at the same time."
   The default track is `1fr`, so four tiles stretch to fill whatever width the page
   has and the number ends up marooned at one end of the tile with its icon at the
   other. Here each tile is capped and the ROW is centred, so a short row of numbers
   sits under the middle of the header instead of being stretched across it.
   ⚠ `minmax(0,220px)` — the 0 floor is what lets a tile shrink on a narrow window;
   `repeat(auto-fit,...)` still re-flows them onto two lines when there is no room.
   ⚠ Deliberately a MODIFIER: both dashboards want the full-width version, and they
   are already owner-approved. Do not move this onto `.pbc-stats` itself. */
.pbc-stats--compact{
  /* ⚠ REVISED 2026-08-08 (§K K-4.33) AFTER THE OWNER LOOKED AT IT. The first cut
     capped each tile at 220px and CENTRED the row, which made the row narrower
     than the page — so the first tile's outline sat well inside the left edge
     while the tab pills below started at the container edge, and the two rows
     read as misaligned. Owner: "all these tabs should start exactly at the same
     line as the first box starts with the outline."
     Four equal 1fr tracks fix all three of their notes at once: the row spans the
     container, so its FIRST and LAST edges land exactly on the tab row's and the
     cards' below (nothing to keep in sync by hand — they share the container);
     each tile ends up a little WIDER than the 220px cap; and the gap grows.
     ⚠ Do not put `justify-content` back — with 1fr tracks there is no free space
     to distribute, and a stale centring rule would be a puzzle for the next
     reader rather than a no-op. */
  grid-template-columns:repeat(4,minmax(0,1fr));
  gap:var(--pbc-space-8);
}
/* `repeat(4,…)` cannot re-flow on its own, so the break points are explicit.
   Two-up before one-up: four tiles going straight to a single column wastes a
   whole screen of height on a tablet. */
@media (max-width:1100px){ .pbc-stats--compact{grid-template-columns:repeat(2,minmax(0,1fr))} }
@media (max-width:560px){  .pbc-stats--compact{grid-template-columns:1fr} }
/* Shorter tiles — owner: "the space on top and on the bottom of those boxes is a
   little bit too much between the content of these boxes and the top and the
   bottom line." The INLINE padding stays at the card's 28px so the number keeps
   its margin from the edge; only the block padding comes in. */
.pbc-stats--compact .pbc-stat{padding-block:var(--pbc-space-5)}
.pbc-stat{
  /* Owner, 2026-07-25: the icon goes in the blank space to the RIGHT of the
     number and label, and bigger than it was on the options page. So the tile is
     a ROW — a text column on the start side, the icon on the end side — rather
     than one stacked column. `space-between` pins the icon to the far edge so
     every tile's icon lines up down the row, whatever width its number is. */
  display:flex;flex-direction:row;align-items:center;justify-content:space-between;
  gap:var(--pbc-space-4);
  padding:var(--pbc-card-pad);
  background:var(--pbc-surface);
  border:var(--pbc-border-width) solid var(--pbc-border);
  border-radius:var(--pbc-radius-card);
  box-shadow:var(--pbc-shadow-xs);
  text-decoration:none;
  color:inherit;
  transition:border-color var(--pbc-transition),box-shadow var(--pbc-transition);
}
/* A tile is a link on the end-user dashboard and a <button> on the Superadmin
   one (four of those open a modal), so reset the button defaults that would
   otherwise show through: browsers give buttons their own font and centring. */
/* ⚠ `min-width:0` FIXES A REAL OVERFLOW — measured 2026-08-02 (§K K-4.10).
   `.pbc-stats` lays out on `repeat(auto-fit,minmax(150px,1fr))`, and `1fr` is
   `minmax(auto,1fr)` — the `auto` floor means a track can never shrink below its
   content's MIN-CONTENT width. A tile with a long label (the case-setup Overview's
   "Request types") plus the 46px icon therefore pushed its track past the container
   and the page grew a horizontal scrollbar. Zeroing the grid ITEM's min-width
   removes that floor so the track can shrink and the label wraps instead.
   The two dashboards never hit it because their labels are short ("Open",
   "Completed") — which is exactly why it survived two screen conversions.
   Same family as the `min-height:0` flex trap in §14.271 add. 2. */
.pbc-stat{font:inherit;text-align:start;width:100%;min-width:0}
/* interactive tiles react to the pointer — both element types */
a.pbc-stat:hover,button.pbc-stat:hover{border-color:var(--pbc-border-strong);box-shadow:var(--pbc-shadow-sm)}
a.pbc-stat:focus-visible,button.pbc-stat:focus-visible{outline:none;box-shadow:var(--pbc-focus-ring)}
button.pbc-stat{cursor:pointer}

/* the number and its label, stacked, on the start side */
.pbc-stat__text{display:flex;flex-direction:column;gap:var(--pbc-space-1);min-width:0}

/* Owner, 2026-07-25: the icons take "the exact same blue as the navigation
   sidebar, which is a darker blue". The sidebar gradient runs from brand-800 to
   brand-950, so its top stop IS --pbc-brand-800 — that is the token, and no new
   hex was invented for it. (I had used steel to
   keep the number the hero; the owner wants the deeper navy, which also makes
   the icon and the number the same colour — brand-800 and --pbc-ink-heading are
   the same value.) 11.65:1 on white, far above the 3:1 bar for graphics. */
/* ⚠⚠ THE COLOUR TOKEN CHANGED brand-800 → ink-heading, 2026-08-02 (§K K-4.10),
   AND IT IS A BUG FIX, NOT A REDESIGN. `--pbc-brand-800` is declared ONLY in
   `:root` — it never flips — so on a dark card the icon measured **1.27:1**:
   invisible. Both dashboards have shipped that way in dark since K-4.2/4.3;
   nothing caught it because the icon is decorative and every contrast harness
   was pointed at text.
   `--pbc-ink-heading` is **#1C3A5A in light — the identical hex to brand-800**,
   so LIGHT MODE DOES NOT MOVE AT ALL, and #EAF1F8 in dark → 12.98:1.
   It also keeps the owner's actual rule from 2026-07-25 ("the icon and the
   number the same colour") true in BOTH themes, because `.pbc-stat__value`
   reads the same token. Do not put brand-800 back. */
.pbc-stat__icon{
  width:var(--pbc-stat-icon);height:var(--pbc-stat-icon);
  flex:none;
  color:var(--pbc-ink-heading);
}
/* The two dashboards use the hand-picked SVG sprite, where width/height size the
   glyph. The sprite has no icon for the case-setup Overview's counts (statuses,
   sections, fields, phases, request types), so that tile uses a Bootstrap Icons
   <i> — and width/height do NOTHING to an icon FONT. Additive: `<svg>` consumers
   are untouched, this only gives the font variant the same box (§K K-4.10). */
i.pbc-stat__icon{font-size:var(--pbc-stat-icon);line-height:1;display:inline-block}
/* Owner, 2026-08-02: this red must MATCH the Critical / overdue badges in the
   Cases Needing Attention list on the same dashboard — see --pbc-danger-alert.
   Not --pbc-danger-500, which also paints the chat unread count, the calendar
   now-indicator and invalid-field borders (all out of scope). */
.pbc-stat--alert .pbc-stat__icon{color:var(--pbc-danger-alert)}

.pbc-stat__value{
  font-family:var(--pbc-font-heading);
  font-weight:var(--pbc-weight-heading);
  font-size:var(--pbc-text-3xl);
  line-height:var(--pbc-leading-tight);
  letter-spacing:var(--pbc-tracking-tight);
  color:var(--pbc-ink-heading);
  font-variant-numeric:tabular-nums;
}
.pbc-stat__label{
  font-size:var(--pbc-text-sm);
  color:var(--pbc-ink-muted);
}
/* a count that means "something needs attention" — applied only when it is
   actually non-zero, so a calm dashboard stays entirely calm.
   The tile is outlined as well as the number coloured: the previous dashboard
   marked an overdue count BOTH ways, and dropping one of the two signals would
   have made the page quieter than the one it replaces. */
/* the headline figure is 32px bold = LARGE text, so the red is fine here
   (needs 3:1, has 4.53 light / 3.26 dark) and matches the icon beside it.
   Owner, 2026-08-02: matched to the badges below — see --pbc-danger-alert. */
.pbc-stat--alert .pbc-stat__value{color:var(--pbc-danger-alert)}
.pbc-stat--alert{border-color:var(--pbc-danger-border)}

/* ==========================================================
   "READ MORE" — keep a widget short, let it open on demand
   ----------------------------------------------------------
   Owner, 2026-07-25: a dashboard widget (Recent activity) ran
   too long. The fix is general, not one-off: show the first
   few entries, hide the rest behind a small control.

   A <details>/<summary> disclosure — no JS, no Bootstrap
   dependency, keyboard-accessible, and the same pattern the
   login language picker uses, so the app keeps ONE way of
   doing this.

   The summary carries BOTH labels and CSS swaps them on
   [open], so the control reads "Read more" / "Show less"
   without a line of script.
   ========================================================== */
.pbc-more{border-top:var(--pbc-border-width) solid var(--pbc-border-subtle)}
.pbc-more > summary{
  list-style:none;
  display:flex;align-items:center;justify-content:center;
  gap:var(--pbc-space-1-5);
  padding-block:var(--pbc-space-3);
  font-size:var(--pbc-text-sm);
  font-weight:var(--pbc-weight-semibold);
  color:var(--pbc-brand-accent);
  cursor:pointer;
  user-select:none;
}
.pbc-more > summary::-webkit-details-marker{display:none}
.pbc-more > summary:hover{background:var(--pbc-surface-hover)}
.pbc-more > summary:focus-visible{outline:none;box-shadow:var(--pbc-focus-ring);border-radius:var(--pbc-radius-xs)}
/* caret, mirrored for RTL by using border tricks rather than a glyph */
.pbc-more > summary::after{
  content:'';
  width:0;height:0;
  border-inline-start:4px solid transparent;
  border-inline-end:4px solid transparent;
  border-top:5px solid currentColor;
  transition:transform var(--pbc-transition);
}
.pbc-more[open] > summary::after{transform:rotate(180deg)}
/* label swap — no script involved */
.pbc-more__less{display:none}
.pbc-more[open] .pbc-more__more{display:none}
.pbc-more[open] .pbc-more__less{display:inline}

/* ==========================================================
   TABLE — genuinely tabular data (numeric columns)
   ----------------------------------------------------------
   Added K-4 (2026-07-25) for the Superadmin dashboard's
   organisation summary, and reused by the case list, reports
   and the audit trail.

   The design vision is "row-cards, not gridlines", and that
   holds for LISTS. This is for data that is actually a table —
   several numeric columns that have to line up to be
   comparable. Row-cards would destroy that alignment.

   So: no vertical rules, hairline horizontal separators only,
   a quiet header, and tabular figures so digits align.

   ⚠ SCOPED: every rule is a descendant of .pbc-table, so this
   never reaches Bootstrap's own .table (which the un-converted
   screens still rely on).
   ========================================================== */
.pbc-table-wrap{width:100%;overflow-x:auto}
.pbc-table{
  width:100%;
  border-collapse:collapse;
  font-size:var(--pbc-text-base);
}
.pbc-table th,
.pbc-table td{
  padding-block:var(--pbc-cell-pad-y);
  padding-inline:var(--pbc-space-4);
  text-align:start;
  border-bottom:var(--pbc-border-width) solid var(--pbc-border-subtle);
  vertical-align:middle;
}
.pbc-table thead th{
  background:var(--pbc-surface-soft);
  color:var(--pbc-ink-muted);
  font-size:var(--pbc-text-xs);
  font-weight:var(--pbc-weight-bold);
  letter-spacing:var(--pbc-tracking-caps);
  text-transform:uppercase;
  white-space:nowrap;
}
.pbc-table tbody tr:last-child td{border-bottom:none}
/* §K K-4.75 (§14.361, 2026-08-23) — a KEY/VALUE table: the first column is the
   label (the Superadmin's "User Details" card, where each row is <th>label</th>
   <td>value</td>). The label column reads like a form label — muted, semibold,
   never wider than a third — so the values carry the weight. Additive modifier;
   a plain .pbc-table is unchanged. */
.pbc-table--kv th{
  width:30%;
  color:var(--pbc-ink-muted);
  font-weight:var(--pbc-weight-semibold);
  font-size:var(--pbc-text-sm);
  background:var(--pbc-surface-soft);
  white-space:nowrap;
}
.pbc-table tbody tr:hover{background:var(--pbc-surface-hover)}
.pbc-table__name{font-weight:var(--pbc-weight-semibold);color:var(--pbc-ink-heading)}
/* numeric column: centred, tabular figures so the digits line up */
.pbc-table__num{
  text-align:center;
  font-variant-numeric:tabular-nums;
}
/* the "nothing here" dash — a real character, not an empty cell */
.pbc-table__none{color:var(--pbc-ink-faint)}
/* trailing action column hugs its content */
.pbc-table__action{text-align:end;white-space:nowrap}
.pbc-table__empty{
  text-align:center;
  color:var(--pbc-ink-muted);
  padding-block:var(--pbc-space-8);
}

/* ==========================================================
   LAYOUT HELPERS — vertical rhythm and dashboard columns
   ----------------------------------------------------------
   Added K-4 (2026-07-25) after the owner said the gaps between
   widget boxes were too tight.

   ⚠ `.pbc-spacer` (further up) is a FLEX spacer —
   margin-inline-start:auto, for pushing an item to the end of a
   row. It does NOT add vertical space. It was used by mistake
   between stacked cards, which is why they sat too close: the
   only gap was Bootstrap's grid gutter.

   `.pbc-stack` is the correct tool: a column whose children are
   separated by the token rhythm.
   ========================================================== */
.pbc-stack{display:flex;flex-direction:column;gap:var(--pbc-space-6)}
.pbc-stack--loose{gap:var(--pbc-section-gap)}

/* Dashboard columns. Deliberately NOT Bootstrap's .row/.col — those bring a
   12-column gutter system the design system already has tokens for, and mixing
   the two is what made the spacing inconsistent. Collapses to one column on
   narrow screens. */
.pbc-cols{
  display:grid;
  grid-template-columns:minmax(0,7fr) minmax(0,5fr);
  gap:var(--pbc-space-6);
  align-items:start;      /* columns size to their own content, no stretching */
}
/* §K K-4.26 — the case page's split: WORK on the left, TOOLS on the right.
   7fr/5fr is right for a dashboard's two equal-weight columns; a case needs a
   wide work column and a narrow rail, so this modifier only changes the track
   sizes and inherits the gap, the alignment and the one-column collapse below. */
.pbc-cols--work{grid-template-columns:minmax(0,2fr) minmax(0,1fr)}
@media (max-width:991px){
  .pbc-cols{grid-template-columns:minmax(0,1fr)}
}

/* ==========================================================
   PILL ROW — a group of pills needs a real gap
   ----------------------------------------------------------
   Pills dropped straight into a container are inline elements
   separated only by whitespace, which collapses to about 4px.
   The owner spotted that in the dashboard modals. Any group of
   pills, chips or badges goes in one of these.
   ========================================================== */
.pbc-pillrow{display:flex;flex-wrap:wrap;gap:var(--pbc-space-2-5)}

/* ==========================================================
   BOOTSTRAP MODAL SHELL, on the design system's spacing
   ----------------------------------------------------------
   Owner, 2026-07-25: "when I click one of the six widget boxes,
   smaller pop-ups open, but the spacing in those is way too
   close — increase it, same as the dashboard."

   Measured before changing anything: header 16px, body 16px,
   footer 12px — against the 28px the dashboard cards use — and
   the blocks inside the body had no rhythm at all (a pill row
   with 0 margin butting straight into the next heading).

   ⚠ THIS STYLES BOOTSTRAP'S OWN CLASSES, which the house rule
   normally forbids. It is scoped to `.modal-content.pbc-scope`,
   i.e. ONLY modals whose content has been converted, so an
   unconverted modal anywhere in the app is untouched. The four
   Superadmin dashboard modals are the only ones today. Do not
   loosen this selector.

   The body becomes a flex column so ONE gap value governs the
   rhythm; the children's own margins are zeroed so margin and
   gap can't stack into uneven spacing.
   ========================================================== */
.modal-content.pbc-scope .modal-header{
  padding:var(--pbc-card-pad) var(--pbc-card-pad) var(--pbc-space-5);
  border-bottom-color:var(--pbc-border);
}
.modal-content.pbc-scope .modal-body{
  padding:var(--pbc-card-pad);
  display:flex;flex-direction:column;
  gap:var(--pbc-space-6);
}
.modal-content.pbc-scope .modal-body > *{margin-block:0}
.modal-content.pbc-scope .modal-footer{
  padding:var(--pbc-space-5) var(--pbc-card-pad);
  gap:var(--pbc-space-3);
  border-top-color:var(--pbc-border);
}
/* a flush table modal keeps its edge-to-edge table — Bootstrap's .p-0 utility
   wins on padding, and the flex column above still gives it a clean single child */
.modal-content.pbc-scope .modal-body.p-0{gap:0}

/* ==========================================================
   CASE ROW — the two-line row-card the case list is built on
   ----------------------------------------------------------
   §K K-4 screen 4 (2026-07-27). REPLACES a 13-column table
   that scrolled sideways on any normal laptop. Composes with
   .pbc-row (hover, focus ring, hairline separator) and only
   overrides the axis: .pbc-row is a centred single-line flex
   row, a case needs a stack.

   Line 1  title ............................ status + pills
   Line 2  #id · type · departments .......... due · updated
   Line 3  current phase · 2 of 5   ▓▓▓░░░░  (only when known)

   Each line is start/end justified, so the pills form a clean
   right-hand column whatever the title length. Logical
   properties throughout — this mirrors for RTL with no
   separate rule.
   ========================================================== */
.pbc-caserow{
  flex-direction:column;align-items:stretch;
  gap:var(--pbc-space-2);
  padding-block:var(--pbc-space-4);
}
.pbc-caserow__line{
  display:flex;align-items:center;justify-content:space-between;
  gap:var(--pbc-space-4);
  min-width:0;
}
/* the title must be free to shrink and ellipsis; the pills never squash */
.pbc-caserow__head{min-width:0;flex:1}
.pbc-caserow__pills{flex:none}
.pbc-caserow__meta{
  font-size:var(--pbc-text-sm);
  color:var(--pbc-ink-muted);
}
.pbc-caserow__facts{
  min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.pbc-caserow__when{flex:none;white-space:nowrap}
/* the phase line: label on the start side, a short bar on the end side */
.pbc-caserow__phase{
  display:flex;align-items:center;gap:var(--pbc-space-3);
  font-size:var(--pbc-text-sm);color:var(--pbc-ink-muted);
}
.pbc-caserow__phase .pbc-progress{flex:none;width:120px}
.pbc-caserow__phasename{
  min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  color:var(--pbc-ink-body);font-weight:var(--pbc-weight-medium);
}
.pbc-caserow__count{flex:none}
/* The row is an <a>, so every child is a <span> — ellipsis and a fixed-height
   bar both need a block box, which an inline span does not have. */
.pbc-caserow .pbc-row__title,
.pbc-caserow__facts,
.pbc-caserow__phasename,
.pbc-caserow .pbc-progress,
.pbc-caserow .pbc-progress__bar{display:block}

/* NARROW — the whole point of the rewrite. Below the breakpoint every line
   stacks instead of the page scrolling sideways. Nothing is hidden. */
@media (max-width:820px){
  /* WRAP, don't hard-stack. Forcing flex-direction:column here put all seven
     pieces of a row on seven lines and made a single case 381px tall, measured.
     Letting each line wrap keeps pairs side by side while they still fit and
     drops only what doesn't — same no-overflow guarantee, a third of the
     height. */
  .pbc-caserow__line{flex-wrap:wrap;gap:var(--pbc-space-2) var(--pbc-space-3)}
  /* long titles get a second line instead of an ellipsis when space is tight */
  .pbc-caserow .pbc-row__title{white-space:normal}
  .pbc-caserow__facts{white-space:normal}
  .pbc-caserow__phase{width:100%}
  .pbc-caserow__phase .pbc-progress{flex:1 1 120px;width:auto}
}

/* ==========================================================
   TAB STATE HOOK — Bootstrap's own .active
   ----------------------------------------------------------
   The case-list tabs keep data-bs-toggle="tab", so BOOTSTRAP
   owns the state and writes .active (not .is-active). Both
   spellings are honoured so the component works whether the
   page drives its tabs itself or hands them to Bootstrap.
   The selector is .pbc-tab.active — compounded with a pbc-
   class, so it never reaches Bootstrap's own .nav-link.
   ========================================================== */
.pbc-tab.active{
  color:var(--pbc-brand-accent);
  border-bottom-color:var(--pbc-brand-accent);
  font-weight:var(--pbc-weight-semibold);
}

/* ==========================================================
   TAB GROUPS — case tabs lead, the rest follow, quieter
   ----------------------------------------------------------
   This page carries four case tabs AND four unrelated ones
   (Info / Offers / Users / Active Requests). At equal weight
   nothing told the user the first four were the same kind of
   thing. .pbc-tabs__rest pushes the others to the end behind
   a divider and drops them a size.
   ========================================================== */
.pbc-tabs{flex-wrap:wrap}
.pbc-tabs__rest{
  margin-inline-start:auto;
  display:flex;align-items:center;gap:var(--pbc-space-5);
  padding-inline-start:var(--pbc-space-5);
  border-inline-start:var(--pbc-border-width) solid var(--pbc-border);
}
.pbc-tabs__rest .pbc-tab{font-size:var(--pbc-text-sm)}
@media (max-width:820px){
  .pbc-tabs__rest{
    margin-inline-start:0;padding-inline-start:0;border-inline-start:none;
    flex-wrap:wrap;
  }
}

/* ==========================================================
   CASE FILTER ROW
   ----------------------------------------------------------
   This screen's OWN filter markup. components/case-filter-bar
   is deliberately NOT restyled — the Superadmin case list
   renders it too (K-4.1 rule 1).
   ========================================================== */
.pbc-casefilter{
  display:flex;align-items:center;flex-wrap:wrap;
  gap:var(--pbc-space-3);
}
/* Both caps are load-bearing, and both were found by measuring the live page:
   without a max the search box absorbed ALL the free space (474px of a 980px
   content column) and a `width:auto` select sized itself to its longest option
   (a long case-setup title pushed it to 262px). Between them the row needed
   1335px and broke onto THREE lines with the count orphaned on the last one.
   NOTHING IN THIS ROW MAY FLEX-GROW, and that is the whole lesson. The result
   count is pushed to the end with margin-inline-start:auto, and an auto margin
   does not reserve space while flex distributes free space — so any growing
   control swallows exactly the room the count needs and orphans it on a line
   of its own. That happened twice, at two different flex bases, before the
   grow factors came off. Fixed widths all round.

   Measured at the real 980px content width: search 190 + 4x145 + button 79 +
   count 50 + six 12px gaps = 971, so it lands on ONE line with 9px to spare. */
.pbc-casefilter .pbc-search{flex:0 1 190px;min-width:170px;max-width:320px}
.pbc-casefilter .pbc-select{flex:0 1 145px;width:auto;min-width:130px;max-width:200px}
.pbc-casefilter__count{
  margin-inline-start:auto;
  font-size:var(--pbc-text-sm);color:var(--pbc-ink-muted);white-space:nowrap;
}
@media (max-width:820px){
  .pbc-casefilter__count{margin-inline-start:0}
  .pbc-casefilter .pbc-select{flex:1 1 150px}
}

/* ==========================================================
   CASE-LIST PAGE FURNITURE
   ----------------------------------------------------------
   Small pieces the case list needs. All additive, all
   pbc-prefixed, none reaching a bare Bootstrap element.
   ========================================================== */

/* breathing room under the tab strip — the standing 24px between blocks */
.pbc-tabbody{padding-top:var(--pbc-space-6)}

/* Info tab: a definition list that wraps into columns instead of the old
   half-width Bootstrap grid cells, which left the card two-thirds empty. */
.pbc-facts{
  display:grid;
  grid-template-columns:repeat(auto-fit,minmax(180px,1fr));
  gap:var(--pbc-space-5);
}
.pbc-facts__item dt{
  font-size:var(--pbc-text-xs);
  font-weight:var(--pbc-weight-bold);
  letter-spacing:var(--pbc-tracking-caps);
  text-transform:uppercase;
  color:var(--pbc-ink-muted);
}
.pbc-facts__item dd{
  margin:var(--pbc-space-1) 0 0;
  font-size:var(--pbc-text-base);
  color:var(--pbc-ink-heading);
}

.pbc-orglogo{
  width:40px;height:40px;flex:none;
  border-radius:var(--pbc-radius-sm);
  object-fit:cover;
}
.pbc-thumb{
  width:64px;height:64px;
  border-radius:var(--pbc-radius-sm);
  object-fit:cover;display:block;
}

/* Request flag chip. ⚠ The BACKGROUND is Superadmin configuration
   (request_flags.color) applied inline, so this rule deliberately sets only
   the shape and the ink. White ink on an arbitrary configured colour is a
   PRE-EXISTING contrast unknown, carried over unchanged from the Bootstrap
   version — it is not something a token can fix. */
.pbc-flag{
  display:inline-flex;align-items:center;
  padding-block:var(--pbc-space-1);
  padding-inline:var(--pbc-space-2-5);
  border-radius:var(--pbc-radius-sm);
  font-size:var(--pbc-text-sm);
  font-weight:var(--pbc-weight-semibold);
  color:var(--pbc-ink-on-brand);
  white-space:nowrap;
}

/* ==========================================================
   DATATABLE TABLES — keep the .pbc-table look after the
   vendor script rewrites the element
   ----------------------------------------------------------
   ⚠ FOUND BY INSPECTING THE LIVE DOM, NOT THE MARKUP.
   simple-datatables (main.js:302) does not merely wrap a
   `.datatable` table — on init it STRIPS the table's original
   classes and replaces them with its own `.datatable-table`.
   So `class="pbc-table datatable"` renders correctly in the
   HTML and then loses every design-system rule the moment the
   script runs. The case list's Offers / Users / Active
   Requests tables all sat unstyled because of it.

   Restated here against the class the vendor actually leaves
   behind. Scoped under `.pbc-table-wrap` so it cannot reach
   any other table in the app; the Superadmin dashboard uses
   `.pbc-table-wrap` too but has no `.datatable` at all, so it
   is provably untouched by this block.

   Dropping the `datatable` class instead would have been the
   easy fix and the wrong one — it is what gives these three
   tables their search, sort and pagination.
   ========================================================== */
.pbc-table-wrap .datatable-table{
  width:100%;
  border-collapse:collapse;
  font-size:var(--pbc-text-base);
}
.pbc-table-wrap .datatable-table th,
.pbc-table-wrap .datatable-table td{
  padding-block:var(--pbc-cell-pad-y);
  padding-inline:var(--pbc-space-4);
  text-align:start;
  border-bottom:var(--pbc-border-width) solid var(--pbc-border-subtle);
  vertical-align:middle;
}
.pbc-table-wrap .datatable-table thead th{
  background:var(--pbc-surface-soft);
  color:var(--pbc-ink-muted);
  font-size:var(--pbc-text-xs);
  font-weight:var(--pbc-weight-bold);
  letter-spacing:var(--pbc-tracking-caps);
  text-transform:uppercase;
  white-space:nowrap;
}
.pbc-table-wrap .datatable-table tbody tr:last-child td{border-bottom:none}
.pbc-table-wrap .datatable-table tbody tr:hover{background:var(--pbc-surface-hover)}

/* ⚠ THE NAME COLUMN NEEDS A FLOOR — §K K-4.30, seen on screen, not deduced.
   simple-datatables sizes columns from content and hands the widest cell the most
   room, so on the organisation page's Cases tab a long department name won ~430px
   while the case TITLE — the thing you actually read down the column — was squeezed
   to ~160px and wrapped onto three lines. The identifying column should never be the
   one that gets crushed.
   Scoped to `.pbc-table__name` inside a datatable, so it reaches only the cells that
   are declared as the row's identity and cannot disturb any plain `.pbc-table`. */
/* ==========================================================
   "+N" OVERFLOW COUNT — one value, then how many more
   ----------------------------------------------------------
   §K K-4.32 (§14.300). Owner's pick C-1 = A from
   `PBC Mockup/org-cases-columns-options.html`, ported from the
   gallery specimen rather than re-derived.

   For a cell that holds a LIST but must stay one line tall:
   print the first value, then this chip for the remainder. It
   is deliberately quiet — the count is a hint that this row is
   the busy one, not a control. `cursor:default` and no hover
   state, because it does nothing when clicked; the full list
   rides its `title`, and the record's own page has all of it.
   ⚠ Contrast measured on the shipped tokens: ink-muted on
   neutral-100 is 5.60:1 light / 6.99:1 dark, so the count
   clears AA as small bold text in both themes.
   ========================================================== */
.pbc-deptcell{
  display:flex;align-items:center;gap:var(--pbc-space-2);
  flex-wrap:wrap;
}
.pbc-plusn{
  display:inline-flex;align-items:center;justify-content:center;
  min-width:26px;height:22px;
  padding-inline:var(--pbc-space-1-5);
  border-radius:var(--pbc-radius-pill);
  background:var(--pbc-neutral-100);
  /* ⚠ THE BORDER IS NOT DECORATION — MEASURED. `--pbc-neutral-100` sits only
     1.24:1 from the row behind it in dark (and ~1.06 in light), so without an
     edge the chip has no shape at all and "+30" reads as part of the department
     name next to it. The border gives it a definite boundary at the app's own
     outline strength in both themes. */
  border:var(--pbc-border-width) solid var(--pbc-border);
  color:var(--pbc-ink-muted);
  font-size:var(--pbc-text-xs);
  font-weight:var(--pbc-weight-bold);
  cursor:default;
}

/* ⚠ Raised 240px → 320px, §K K-4.31: the owner still found the case NAME column
   "too narrow… it gets into many lines" at 240. The identifying column carries a
   subject's full name plus its `#id · setup` sub-line, so it needs the most room on
   the row, not the least. */
.pbc-table-wrap .datatable-table td.pbc-table__name,
.pbc-table-wrap .datatable-table th:first-child{min-width:320px}

/* the vendor's own chrome (search box, page-size selector, pager) sits
   OUTSIDE the table. Give it the card's padding so it is not flush to the edge. */
.pbc-table-wrap .datatable-top,
.pbc-table-wrap .datatable-bottom{padding:var(--pbc-space-4)}
/* K-4.82 (§14.374) — the K-5 carry-over closed: the chrome is on the house
   control shape everywhere, not only on the case page (which carried these
   three rules page-scoped since CW-8a, §14.347). SHAPE only: dark-mode.css
   paints these controls at (0,2,1) and keeps the colours — deliberate. */
.pbc-table-wrap .datatable-input,
.pbc-table-wrap .datatable-selector{
  border:var(--pbc-border-width) solid var(--pbc-border);
  border-radius:var(--pbc-radius-btn);
  background:var(--pbc-surface);
  color:var(--pbc-ink-body);
  font-family:inherit;
  font-size:var(--pbc-text-sm);
  height:var(--pbc-control-h-sm);
  padding-inline:var(--pbc-space-3);
}
.pbc-table-wrap .datatable-input:focus-visible,
.pbc-table-wrap .datatable-selector:focus-visible{outline:none;box-shadow:var(--pbc-focus-ring)}
.pbc-table-wrap .datatable-pagination a{border-radius:var(--pbc-radius-btn)}
.pbc-table-wrap .datatable-container{border-color:var(--pbc-border-subtle)}

/* ==========================================================
   CATEGORY PILLS — the case list's My Work / My Cases /
   Mentions / Archived switcher
   ----------------------------------------------------------
   Owner chose this over underline tabs (2026-07-27): the thin
   underlined tabs read as links, not as "pick one of four".
   The selected one is a solid brand-600 fill with white ink
   (6.73:1 — the app's approved solid fill; never brand-500,
   which is only 3.91:1 under white).

   Bootstrap still owns the tab machinery via data-bs-toggle,
   so it writes `.active`. Both spellings are honoured, the
   same as .pbc-tab.
   ========================================================== */
.pbc-catpills{display:flex;align-items:center;gap:var(--pbc-space-2);flex-wrap:wrap;list-style:none;margin:0;padding:0}
.pbc-catpill{
  display:inline-flex;align-items:center;gap:var(--pbc-space-2);
  border:var(--pbc-border-width) solid var(--pbc-border);
  background:var(--pbc-surface);
  color:var(--pbc-ink-body);
  font-family:inherit;font-size:var(--pbc-text-base);font-weight:var(--pbc-weight-medium);
  padding-block:var(--pbc-space-2-5);
  padding-inline:var(--pbc-space-5);
  border-radius:var(--pbc-radius-pill);
  cursor:pointer;white-space:nowrap;
  transition:background-color var(--pbc-transition),border-color var(--pbc-transition),color var(--pbc-transition);
}
.pbc-catpill:hover{border-color:var(--pbc-border-strong);background:var(--pbc-surface-hover)}
/* §K A1 permanent (K-4.67) — a NON-active pill's label must not be repainted by
   Bootstrap's reboot `a:hover` (0,1,1). The :not() guards keep this off the ACTIVE
   pill, which already declares its own colour. Moved here from pbc-theme.css. */
.pbc-catpill:not(.active):not(.is-active):hover{color:var(--pbc-ink-body)}
.pbc-catpill:focus-visible{outline:none;box-shadow:var(--pbc-focus-ring)}
.pbc-catpill.active,
.pbc-catpill.is-active{
  background:var(--pbc-brand-600);
  border-color:var(--pbc-brand-600);
  color:var(--pbc-ink-on-brand);
  font-weight:var(--pbc-weight-semibold);
}
.pbc-catpill.active:hover,
.pbc-catpill.is-active:hover{background:var(--pbc-brand-700);border-color:var(--pbc-brand-700)}
/* the count rides along inside the pill and inherits its ink */
.pbc-catpill__n{font-size:var(--pbc-text-xs);font-weight:var(--pbc-weight-bold);opacity:.85}
/* the four tabs that are NOT case lists sit after a divider, quieter */
.pbc-catpills__rest{
  margin-inline-start:auto;
  display:flex;align-items:center;gap:var(--pbc-space-4);
  padding-inline-start:var(--pbc-space-5);
  border-inline-start:var(--pbc-border-width) solid var(--pbc-border);
}
/* Size and spacing apply to every pill in the demoted group, SELECTED OR NOT —
   the demoted family stays visually smaller either way. */
.pbc-catpills__rest .pbc-catpill{
  font-size:var(--pbc-text-sm);
  padding-inline:var(--pbc-space-3);
}
/* ⚠⚠ THE `:not(.active):not(.is-active)` IS LOAD-BEARING — DO NOT REMOVE IT.
   §K K-4.29 (§14.297), found by measuring, not by looking at the CSS.
   `.pbc-catpills__rest .pbc-catpill` and `.pbc-catpill.active` carry the SAME
   specificity (0,2,0) and this rule sits LATER in the file, so source order used
   to win: a SELECTED pill in the demoted group had its brand fill stripped back
   to transparent while it kept `color:var(--pbc-ink-on-brand)` — white ink on the
   light canvas, measured at 1.17:1. The selected tab was invisible.
   Latent on the approved end-user case list (its Info/Offers/Users tabs live in
   this group); permanent on the Superadmin organisation page, whose default tab
   IS one of the demoted four. Every static check passed. */
.pbc-catpills__rest .pbc-catpill:not(.active):not(.is-active){
  border-color:transparent;background:transparent;
}
.pbc-catpills__rest .pbc-catpill:not(.active):not(.is-active):hover{background:var(--pbc-surface-hover);border-color:transparent}
@media (max-width:820px){
  .pbc-catpills__rest{margin-inline-start:0;padding-inline-start:0;border-inline-start:none;flex-wrap:wrap}
}

/* ONE ROW, ALWAYS — owner, 2026-08-08 (§K K-4.28). A wrapping pill row strands a
   half-row of tabs in the middle of the page, which is what got the organisation
   page's first cut rejected. With this modifier the row never wraps: if the pills
   are wider than the page it scrolls sideways instead, which keeps them reading
   as one family. Use it on any tab strip that must stay on a single line.
   ⚠ `flex:none` on the items is required — flex children shrink by default, and a
   squeezed pill would ellipsise its label rather than let the row scroll. */
.pbc-catpills--nowrap{
  flex-wrap:nowrap;
  overflow-x:auto;
  overscroll-behavior-x:contain;
  scrollbar-width:thin;
  /* room for the scrollbar so it never sits on top of a pill's border */
  padding-block-end:var(--pbc-space-1);
}
.pbc-catpills--nowrap > li{flex:none}
/* Tighter side padding, because a one-line row has to earn its width. Measured,
   not guessed: with the default 20px the organisation page's ten pills came to
   1253px against 1132px of row — 121px over, so two of them sat off-screen behind
   a scrollbar. At 12px the same ten measure 1092px and the row fits with room to
   spare, while a narrow window still scrolls rather than wrapping.
   ⚠ The FONT SIZE is untouched — these are full-strength pills, just less padded.
   Shrinking the text is what made the first cut's demoted group read as secondary,
   which is exactly what the owner rejected. */
.pbc-catpills--nowrap .pbc-catpill{padding-inline:var(--pbc-space-3)}

/* ==========================================================
   STRIPED CASE TABLE — .pbc-table with alternating rows,
   a darker cursor row, and optional status group headers
   ----------------------------------------------------------
   Owner-approved layout, 2026-07-27. Extends .pbc-table rather
   than forking it, so the Superadmin dashboard's tables and
   this one stay one component.

   ⚠⚠ SOURCE ORDER IS LOAD-BEARING IN THIS BLOCK. The stripe
   and the hover rules carry the SAME specificity, so hover
   MUST stay last or a shaded row would never light up under
   the cursor. Do not reorder or "tidy" these five rules.

   ⚠ The stripe is stamped SERVER-SIDE as .is-alt rather than
   with :nth-child, because when the list is grouped the
   striping restarts inside each group — nth-child counts
   across the whole tbody and cannot do that.
   ========================================================== */
.pbc-table--zebra tbody tr.pbc-crow{background:var(--pbc-surface)}
.pbc-table--zebra tbody tr.pbc-crow.is-alt{background:var(--pbc-row-stripe)}
.pbc-table--zebra tbody tr.pbc-crow{cursor:pointer}
/* keep the cursor row legible: the whole row lifts, including the striped one */
.pbc-table--zebra tbody tr.pbc-crow:hover,
.pbc-table--zebra tbody tr.pbc-crow.is-alt:hover{background:var(--pbc-row-hover)}

/* status group header — the SAME blue as the selected category pill (owner,
   2026-07-27; it was navy and read as too dark). Not surface-soft, which would
   land within a few shades of the stripe and stop reading as a divider.
   White ink 6.73 on the fill; the fill stays 6.14 clear of the stripe and
   5.53 clear of the hover row. */
.pbc-table__group td{
  background:var(--pbc-brand-600);
  color:var(--pbc-ink-on-brand);
  padding-block:var(--pbc-space-2-5);
  border-bottom:none;
}
.pbc-table__group-in{display:flex;align-items:center;gap:var(--pbc-space-3)}
.pbc-table__group-t{
  font-size:var(--pbc-text-xs);font-weight:var(--pbc-weight-bold);
  letter-spacing:var(--pbc-tracking-caps);text-transform:uppercase;
}
.pbc-table__group-n{
  font-size:var(--pbc-text-xs);font-weight:var(--pbc-weight-bold);
  background:var(--pbc-on-brand-fill);
  border-radius:var(--pbc-radius-pill);
  padding:1px 9px;
}

/* the case cell: title with the id + type beneath it.

   ⚠⚠ THE LONG SELECTOR IS DELIBERATE — FOURTH TIME THE LEGACY RE-SKIN HAS
   OUT-SPECIFIED THE COMPONENT LAYER. The title is an <a>, and
   `pbc-theme.css:108` is `body.pbc-skin a:not(.btn):not(.pbc-btn){color:#2C5F8C}`
   at specificity (0,3,2) — it painted every case title brand blue instead of
   the navy heading colour the owner approved in the concept. A plain
   `.pbc-ccase__t` is (0,1,0) and loses. This selector is (0,3,3) and wins
   WITHOUT editing the shared legacy file, so no other screen is affected.
   Do not "simplify" it back. (Blue titles were legible — 6.73/6.14/5.53 across
   the three row states — this is about matching what was signed off.) */
.pbc-scope .pbc-table--zebra tbody td a.pbc-ccase__t,
.pbc-ccase__t{font-weight:var(--pbc-weight-semibold);color:var(--pbc-ink-heading);display:block;text-decoration:none}
.pbc-scope .pbc-table--zebra tbody td a.pbc-ccase__t:hover{color:var(--pbc-brand-700);text-decoration:underline}
.pbc-ccase__s{font-size:var(--pbc-text-sm);color:var(--pbc-ink-muted);display:block;margin-top:2px}
/* the phase cell: name, x/y, then a short bar */
.pbc-cphase{display:flex;align-items:center;gap:var(--pbc-space-2);min-width:0}
.pbc-cphase__n{font-size:var(--pbc-text-sm);color:var(--pbc-ink-body);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* ⚠ ink-MUTED, never ink-faint: faint measures 4.33:1 on the hover row. */
.pbc-cphase__of{font-size:var(--pbc-text-xs);color:var(--pbc-ink-muted);font-variant-numeric:tabular-nums;white-space:nowrap}
.pbc-cphase .pbc-progress{width:64px;flex:none}
/* due / updated */
.pbc-cdate{font-variant-numeric:tabular-nums;color:var(--pbc-ink-muted);font-size:var(--pbc-text-sm);white-space:nowrap}
.pbc-cdate--late{color:var(--pbc-danger-600);font-weight:var(--pbc-weight-semibold)}
.pbc-cdate--soon{color:var(--pbc-warning-600);font-weight:var(--pbc-weight-semibold)}
.pbc-cplain{color:var(--pbc-ink-muted);font-size:var(--pbc-text-sm)}

/* the toolbar row that carries the pills and the New Case button */
.pbc-listbar{display:flex;align-items:center;gap:var(--pbc-space-4);flex-wrap:wrap;margin-bottom:var(--pbc-space-6)}
/* the group-by control sits with the filters */
.pbc-groupby{display:inline-flex;align-items:center;gap:var(--pbc-space-2);white-space:nowrap}

@media (max-width:900px){
  /* drop the two least-critical columns before the table can overflow */
  .pbc-table--zebra th.pbc-col-opt,
  .pbc-table--zebra td.pbc-col-opt{display:none}
}

/* ==========================================================
   APP SHELL — sidebar + top bar        (§K K-4.5, 2026-07-29)
   ==========================================================
   The frame every screen sits inside. Shared by 106 screens (36 end-user,
   70 Superadmin), which is why it is the highest-leverage conversion in §K.

   ── THE MASTER SWITCH ─────────────────────────────────────────────────
   Everything here is scoped under `body.pbc-shell`, which both master
   layouts now emit. REMOVING THAT ONE CLASS REVERTS THE ENTIRE SHELL to
   the legacy look — no CSS was deleted to build this, only out-scoped:
     • pbc-theme.css shell rules are now `:not(.pbc-shell)`
     • the masters' inline #main/#sidebar offsets are now `:not(.pbc-shell)`
   That is deliberate. This change touches every screen in the app, so it
   needed a one-token undo.

   ── THE ARRANGEMENT (owner-approved 2026-07-29) ───────────────────────
   The sidebar runs the FULL height of the window and carries the
   organisation identity at its head. The top bar starts where the sidebar
   ends — it no longer spans the full width — and drops from 105px to
   62px, which returns 43px of vertical space to all 106 screens.

   ── WHAT MUST NOT BE RENAMED ──────────────────────────────────────────
   These hooks are load-bearing for JS that lives elsewhere. The markup
   keeps them and this file styles them where they sit:
     #header #sidebar #main #footer  — main.js (.header-scrolled, echarts
                                       ResizeObserver) and pbc-global-notify.js
                                       (the dirty-guard ignores inputs inside
                                       #sidebar/#header)
     .toggle-sidebar-btn            — main.js toggles body.toggle-sidebar
     .search-bar / .search-bar-show — main.js small-screen search reveal
     #sidebar-nav .nav-link         — the active-link script
     .collapsed                     — INVERTED: the script puts .collapsed on
                                      every INACTIVE link, so "active" is
                                      `.nav-link:not(.collapsed)`
     .header-nav .notifications/.profile — the bell + account dropdown panels
     .dark-mode-toggle              — the masters' dark-mode script
   ========================================================== */

/* ── Geometry ─────────────────────────────────────────────────────────
   The sidebar width and the matching offsets of the top bar, the content and
   the footer are declared PER STATE, with the width token itself.

   ⚠ WHY THESE ARE DECLARED PER STATE RATHER THAN THROUGH ONE SHARED
   `--pbc-shell-side` VARIABLE FLIPPED ON <body>:
   a transitioned property whose value arrives through an INHERITED CUSTOM
   PROPERTY is a known browser-invalidation hazard — the winning declaration's
   own text never changes when only the variable does, so the transition has
   nothing to key off. Declaring the collapsed geometry outright means the
   winning DECLARATION changes, which is unambiguous in every engine.

   ⚠ AND WHY EACH SHELL ELEMENT RE-DECLARES ITS OWN `transition`:
   style.css puts a blanket `transition:all 0.3s` on #main and `all 0.5s` on
   .header. Blanket transitions animate properties that should snap (they also
   drag the background-colour through a 300ms fade on every dark-mode switch).
   Each shell element below narrows that to the one geometry property it
   actually moves.

   ⚠ VERIFYING THIS: the Claude Browser pane FREEZES CSS TRANSITIONS — a probe
   element with a plain 200ms width transition never advances past its start
   value, though getAnimations() reports one registered. Any transitioned
   property therefore MEASURES AS ITS OLD VALUE FOREVER in that pane, which
   looks exactly like a broken layout and is not one. To check shell geometry
   there, set `transition:none` on the element first, then read it. */

/* ── The sidebar shell ────────────────────────────────────────────────
   Specificity note: `body.pbc-shell #sidebar.sidebar` is (1,3,1). It has to
   beat style.css `.sidebar` (0,1,0), rtl.css `[dir="rtl"] .sidebar` (0,2,0)
   AND pbc-theme's `body.pbc-skin .sidebar` (0,2,1) — the last of which uses
   !important on colour, which is why pbc-theme's sidebar block is now
   out-scoped with :not(.pbc-shell) rather than fought here. */
body.pbc-shell #sidebar.sidebar{
  position:fixed;
  top:0;bottom:0;
  /* Logical, so Arabic mirrors without a second stylesheet. These beat
     rtl.css's hand-mirrored left/right on specificity. */
  inset-inline-start:0;
  inset-inline-end:auto;
  width:var(--pbc-sidebar-w);
  padding:0;
  background:var(--pbc-sidebar-bg);
  border-inline-end:var(--pbc-border-width) solid var(--pbc-sidebar-border);
  border-inline-start:none;
  box-shadow:none;
  display:flex;
  flex-direction:column;
  overflow:hidden;              /* the nav scrolls; the org head + foot pin */
  z-index:996;                  /* unchanged from style.css */
  transition:width var(--pbc-duration-base) var(--pbc-ease-standard),
             inset-inline-start var(--pbc-duration-base) var(--pbc-ease-standard);
}

/* Organisation identity — the head of the sidebar. Height is locked to the
   top bar so the two form one unbroken horizontal line across the screen. */
body.pbc-shell .pbc-side__org{
  display:flex;align-items:center;gap:var(--pbc-space-3);
  min-height:var(--pbc-topbar-h);
  box-sizing:border-box;
  padding:var(--pbc-space-3) var(--pbc-space-4);
  border-bottom:var(--pbc-border-width) solid var(--pbc-sidebar-border);
  text-decoration:none;
  flex:none;
}
body.pbc-shell .pbc-side__org:hover{background:var(--pbc-sidebar-hover)}
body.pbc-shell .pbc-side__mark{
  width:34px;height:34px;flex:none;
  border-radius:var(--pbc-radius-sm);
  background:var(--pbc-on-brand-fill);
  border:var(--pbc-border-width) solid var(--pbc-on-brand-border);
  display:grid;place-items:center;overflow:hidden;
  color:var(--pbc-sidebar-ink-strong);
  font-family:var(--pbc-font-heading);
  font-weight:var(--pbc-weight-heading);
  font-size:var(--pbc-text-sm);
}
body.pbc-shell .pbc-side__mark img{
  width:100%;height:100%;object-fit:contain;display:block;
}
/* Owner request 2026-08-02 — the Superadmin sidebar carries the finished woven
   PBC mark, which already has its own edge, so the chip frame above read as a
   second outline around it. This variant drops only the fill + border; the
   34px footprint (and therefore the whole head row's alignment) is unchanged,
   because the border keeps its width and only loses its colour. Applied via
   .pbc-side__mark--plain in pbc-admin/layout/sidebar.blade.php ONLY — the
   end-user sidebar still needs the frame behind its initials fallback. */
body.pbc-shell .pbc-side__mark--plain{
  background:transparent;
  border-color:transparent;
}
body.pbc-shell .pbc-side__txt{min-width:0}
body.pbc-shell .pbc-side__name{
  font-family:var(--pbc-font-heading);
  font-weight:var(--pbc-weight-heading);
  font-size:var(--pbc-text-base);
  letter-spacing:var(--pbc-tracking-tight);
  /* 10.2:1 on the top of the sidebar gradient. NEVER brand-500 here — that
     is 2.98:1 and unreadable (locked design rule). */
  color:var(--pbc-sidebar-ink-strong);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  line-height:var(--pbc-leading-tight);
}
body.pbc-shell .pbc-side__sub{
  font-size:var(--pbc-text-xs);
  color:var(--pbc-sidebar-ink);          /* 5.64:1 at the gradient top */
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  line-height:var(--pbc-leading-tight);
  margin-top:2px;
}

/* The nav column — the only part that scrolls. */
body.pbc-shell #sidebar-nav{
  flex:1;
  overflow-y:auto;
  overflow-x:hidden;
  padding:var(--pbc-space-3);
  margin:0;
  scrollbar-width:thin;
  scrollbar-color:var(--pbc-brand-700) transparent;
}
body.pbc-shell #sidebar-nav::-webkit-scrollbar{width:5px}
body.pbc-shell #sidebar-nav::-webkit-scrollbar-thumb{
  background-color:var(--pbc-brand-700);border-radius:var(--pbc-radius-pill);
}
body.pbc-shell #sidebar-nav::-webkit-scrollbar-track{background:transparent}

/* Group heading. Hidden automatically when its whole group is permission-
   filtered away — see .pbc-nav__head:not(:has(...)) at the end of this block. */
body.pbc-shell .pbc-nav__head{
  font-size:var(--pbc-text-xs);
  font-weight:var(--pbc-weight-bold);
  letter-spacing:var(--pbc-tracking-caps);
  text-transform:uppercase;
  /* brand-300 at full strength = 5.64:1. Do not add opacity — at .8 this
     11.5px uppercase label drops to 4.21:1. */
  color:var(--pbc-brand-300);
  padding:var(--pbc-space-2) var(--pbc-space-3);
  margin-top:var(--pbc-space-3);
  white-space:nowrap;
}
body.pbc-shell #sidebar-nav > .pbc-nav__head:first-child{margin-top:0}

/* Nav rows. Remember: .collapsed = INACTIVE (the active-link script's
   convention), so the plain selector is the resting state and
   :not(.collapsed) is the current page. */
body.pbc-shell #sidebar-nav .nav-item{margin-bottom:0}
body.pbc-shell #sidebar-nav .nav-link{
  display:flex;align-items:center;gap:var(--pbc-space-3);
  padding-block:var(--pbc-space-2-5);
  padding-inline:var(--pbc-space-3);
  border-radius:var(--pbc-radius-sm);
  color:var(--pbc-sidebar-ink);
  background:transparent;
  font-size:var(--pbc-text-base);
  font-weight:var(--pbc-weight-medium);
  text-decoration:none;
  white-space:nowrap;
  margin-bottom:var(--pbc-space-1);
  border:none;
  transition:background-color var(--pbc-transition),color var(--pbc-transition);
}
body.pbc-shell #sidebar-nav .nav-link i{
  font-size:16px;
  width:18px;flex:none;text-align:center;
  color:inherit;                /* legacy style.css paints these #4154f1 */
  margin:0;
}
body.pbc-shell #sidebar-nav .nav-link:hover{
  background:var(--pbc-sidebar-hover);
  color:var(--pbc-sidebar-ink-strong);
}
body.pbc-shell #sidebar-nav .nav-link:hover i{color:var(--pbc-sidebar-ink-strong)}
body.pbc-shell #sidebar-nav .nav-link:not(.collapsed){
  background:var(--pbc-sidebar-active);
  color:var(--pbc-sidebar-ink-strong);
  font-weight:var(--pbc-weight-semibold);
  position:relative;
}
/* §K A3 / NV-1 D (§14.336, 2026-08-18) — the owner could not see which page they
   were on. The fill alone was the whole signal and it sat 1.09:1 from the hover
   shade; NV-1 D adds a second, non-colour signal so the answer survives a glance,
   colour-blindness, greyscale printing and forced-colours mode.
   ⚠ THE BAR IS --pbc-brand-300, NOT --pbc-brand-accent. In light mode that alias
   resolves to brand-600 (#2C5F8C), which is 1.73:1 on this navy — an invisible
   bar. The gallery's first draft shipped exactly that and it was caught only by
   looking at it. brand-300 is 5.64:1 here and is already what `.pbc-nav__group`
   uses on this same surface.
   ⚠ NO `overflow:hidden` to contain the bar inside the 8px radius. The rule above
   sets `white-space:nowrap`, so clipping would SILENTLY TRUNCATE long nav labels —
   a behaviour change smuggled into a colour fix. The bar is inset 6px top and
   bottom instead, which keeps it inside the corners and clips nothing.
   ⚠ `::before` + `inset-inline-start`, NOT `box-shadow:inset`. The shadow version
   is tidier but physical-left-only, so it would put the bar on the wrong side in
   Arabic; this codebase has no RTL sheet and relies on logical properties.
   ★ Twin rule on `.pbc-nav__item.is-active` earlier in this file — change both. */
body.pbc-shell #sidebar-nav .nav-link:not(.collapsed)::before{
  content:"";
  position:absolute;
  inset-inline-start:0;
  top:6px;
  bottom:6px;
  width:3px;
  border-radius:0 2px 2px 0;
  background:var(--pbc-brand-300);
}
body.pbc-shell #sidebar-nav .nav-link:not(.collapsed) i{color:var(--pbc-sidebar-ink-strong)}
body.pbc-shell #sidebar-nav .nav-link:focus-visible{
  outline:none;box-shadow:var(--pbc-focus-ring);
}
/* The label; hidden in rail mode. */
body.pbc-shell .pbc-nav__label{
  overflow:hidden;text-overflow:ellipsis;min-width:0;
}
/* Counts (chat unread, pending resets) sit at the far end of the row. */
body.pbc-shell .pbc-nav__count{
  margin-inline-start:auto;
  flex:none;
  font-size:var(--pbc-text-xs);
  font-weight:var(--pbc-weight-bold);
  background:var(--pbc-on-brand-fill);
  border:var(--pbc-border-width) solid var(--pbc-on-brand-border);
  color:var(--pbc-sidebar-ink-strong);
  border-radius:var(--pbc-radius-pill);
  padding-inline:var(--pbc-space-2);
  line-height:18px;
  min-width:22px;text-align:center;
}
/* A count that reads 0 carries no information.
   ⚠ It cannot be hidden by EMPTYING the element: pbc-chat.js and
   pbc-global-notify.js both parseInt this element's textContent and guard on
   Number.isFinite, so an empty string would silently kill every later
   increment. The sidebar blade keeps a real number in there and toggles
   .is-zero instead (server-rendered, then watched by a MutationObserver). */
body.pbc-shell .pbc-nav__count:empty,
body.pbc-shell .pbc-nav__count.is-zero{display:none}

/* Foot of the sidebar — the "Powered by PBC" credit. Owner decision
   2026-07-29: the credit lives HERE (permanently visible) and the page
   footer keeps only the copyright line, so it is never printed twice. */
body.pbc-shell .pbc-side__foot{
  flex:none;
  padding:var(--pbc-space-4);
  border-top:var(--pbc-border-width) solid var(--pbc-sidebar-border);
  font-size:var(--pbc-text-xs);
  color:var(--pbc-sidebar-ink);           /* 7.81:1 at the gradient foot */
  white-space:nowrap;
  overflow:hidden;
}
body.pbc-shell .pbc-side__foot b{
  color:var(--pbc-sidebar-ink-strong);
  font-family:var(--pbc-font-heading);
  font-weight:var(--pbc-weight-bold);
}

/* ── Collapsed = a 72px icon rail (NOT a disappearing sidebar) ─────────
   The old behaviour deleted the sidebar outright on desktop. Now every
   icon survives; only the words go. */
@media (min-width:1200px){
  /* The rail's geometry, declared outright — see the warning at the top of
     this section for why this cannot be a variable flip. */
  body.pbc-shell.toggle-sidebar #sidebar.sidebar{width:var(--pbc-sidebar-w-collapsed)}
  body.pbc-shell.toggle-sidebar #header.header{inset-inline-start:var(--pbc-sidebar-w-collapsed)}
  body.pbc-shell.toggle-sidebar #main.main,
  body.pbc-shell.toggle-sidebar #footer.footer{margin-inline-start:var(--pbc-sidebar-w-collapsed)}

  body.pbc-shell.toggle-sidebar .pbc-nav__label,
  body.pbc-shell.toggle-sidebar .pbc-nav__count,
  body.pbc-shell.toggle-sidebar .pbc-nav__head,
  body.pbc-shell.toggle-sidebar .pbc-side__txt,
  body.pbc-shell.toggle-sidebar .pbc-side__foot span{display:none}

  body.pbc-shell.toggle-sidebar #sidebar-nav .nav-link{
    justify-content:center;
    padding-inline:0;
  }
  body.pbc-shell.toggle-sidebar .pbc-side__org{
    justify-content:center;
    padding-inline:0;
  }
  body.pbc-shell.toggle-sidebar .pbc-side__foot{
    text-align:center;padding-inline:0;
  }
  /* Group headings vanish in rail mode, so keep the groups readable as
     groups with a hairline where each heading used to be. */
  body.pbc-shell.toggle-sidebar #sidebar-nav .pbc-nav__head + .nav-item{
    border-top:var(--pbc-border-width) solid var(--pbc-sidebar-border);
    padding-top:var(--pbc-space-2);
    margin-top:var(--pbc-space-2);
  }
  body.pbc-shell.toggle-sidebar #sidebar-nav > .pbc-nav__head:first-child + .nav-item{
    border-top:none;padding-top:0;margin-top:0;
  }
}

/* ── The top bar ──────────────────────────────────────────────────────
   Starts where the sidebar ends. `inset-inline-start` has to out-specify
   Bootstrap's .fixed-top{left:0} — (1,3,1) vs (0,1,0), so it does. */
body.pbc-shell #header.header{
  height:var(--pbc-topbar-h);
  inset-inline-start:var(--pbc-sidebar-w);
  inset-inline-end:0;
  padding:0 var(--pbc-space-5);
  gap:var(--pbc-space-4);
  background:var(--pbc-surface);
  border-bottom:var(--pbc-border-width) solid var(--pbc-border);
  box-shadow:var(--pbc-shadow-xs);
  z-index:997;                  /* unchanged from style.css */
  transition:inset-inline-start var(--pbc-duration-base) var(--pbc-ease-standard);
}
/* main.js adds .header-scrolled past 100px — keep it from re-shadowing. */
body.pbc-shell #header.header.header-scrolled{box-shadow:var(--pbc-shadow-sm)}

body.pbc-shell .pbc-top__burger{
  font-size:22px;line-height:1;flex:none;cursor:pointer;
  color:var(--pbc-ink-muted);
  padding:var(--pbc-space-1);
  border-radius:var(--pbc-radius-xs);
}
body.pbc-shell .pbc-top__burger:hover{color:var(--pbc-brand-600);background:var(--pbc-surface-hover)}

/* Page name. Filled in by the active-link script from whichever nav item
   matches the current URL, so no page file has to declare it. */
body.pbc-shell .pbc-top__title{
  font-family:var(--pbc-font-heading);
  font-weight:var(--pbc-weight-heading);
  font-size:var(--pbc-text-lg);
  letter-spacing:var(--pbc-tracking-tight);
  color:var(--pbc-ink-heading);
  white-space:nowrap;
  flex:none;
}
body.pbc-shell .pbc-top__title:empty{display:none}

/* Organisation identity repeated in the bar — SMALL SCREENS ONLY, where
   the sidebar (which normally carries it) is off-canvas. Without this you
   lose all sense of whose system you are in on a phone. */
body.pbc-shell .pbc-top__org{
  display:none;
  align-items:center;gap:var(--pbc-space-2-5);
  /* shrink-only, for the same reason as .search-bar above */
  flex:0 1 auto;
  min-width:0;text-decoration:none;
}
body.pbc-shell .pbc-top__org .pbc-top__orgmark{
  width:28px;height:28px;flex:none;border-radius:var(--pbc-radius-xs);
  background:var(--pbc-brand-600);color:var(--pbc-ink-on-brand);
  display:grid;place-items:center;overflow:hidden;
  font-family:var(--pbc-font-heading);font-weight:var(--pbc-weight-bold);
  font-size:var(--pbc-text-xs);
}
body.pbc-shell .pbc-top__org .pbc-top__orgmark img{width:100%;height:100%;object-fit:contain;display:block}
body.pbc-shell .pbc-top__org .pbc-top__orgname{
  font-family:var(--pbc-font-heading);font-weight:var(--pbc-weight-heading);
  font-size:var(--pbc-text-base);color:var(--pbc-ink-heading);
  letter-spacing:var(--pbc-tracking-tight);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}

/* ── Search ───────────────────────────────────────────────────────────
   The .search-bar wrapper is what main.js's small-screen reveal toggles.
   It did not exist before, so `select('.search-bar').classList` threw a
   TypeError on every tap of the search icon — a live crash that fell out
   when this markup was rebuilt (logged as a carry-over fix, not a feature). */
/* ⚠ `flex:0 1 380px` — BASIS, NOT GROW, and this is not a style preference.
   `.header-nav` is pushed to the far end with `margin-inline-start:auto`, and an
   auto margin does NOT reserve space while flex distributes free space. Any
   sibling allowed to grow swallows exactly the room the actions need and
   orphans them onto a second line. Same trap the case row hit (§14.265). */
body.pbc-shell .search-bar{
  min-width:0;
  padding:0;
  flex:0 1 380px;
  display:flex;align-items:center;
}
body.pbc-shell #pbcCaseSearchForm{width:100%;margin:0}
body.pbc-shell #pbcCaseSearchForm .input-group{
  border:var(--pbc-border-width) solid var(--pbc-border);
  background:var(--pbc-surface-soft);
  border-radius:var(--pbc-radius-btn);
  overflow:hidden;
  transition:border-color var(--pbc-transition),box-shadow var(--pbc-transition);
}
body.pbc-shell #pbcCaseSearchForm .input-group:hover{border-color:var(--pbc-border-strong)}
body.pbc-shell #pbcCaseSearchForm .input-group:focus-within{
  border-color:var(--pbc-brand-600);
  box-shadow:var(--pbc-focus-ring);
}
body.pbc-shell #pbcCaseSearchForm .input-group-text{
  background:transparent;border:none;
  color:var(--pbc-ink-muted);
  padding-inline:var(--pbc-space-3);
}
body.pbc-shell #pbcCaseSearchForm .form-control{
  background:transparent;border:none;box-shadow:none;
  font-family:var(--pbc-font-body);
  font-size:var(--pbc-text-base);
  color:var(--pbc-ink-body);
  padding-block:var(--pbc-space-2);
  padding-inline:0 var(--pbc-space-3);
}
/* ⚠ ink-MUTED, not ink-faint: ink-faint on surface-soft measures 4.46:1 in
   dark mode, just under AA. ink-muted clears both themes (5.62 / 7.05). */
body.pbc-shell #pbcCaseSearchForm .form-control::placeholder{
  color:var(--pbc-ink-muted);opacity:1;
}
/* The live results dropdown (pbc-case-search.js fills it; the .pbc-cs-*
   inner classes are declared inline in the header blades). */
body.pbc-shell .pbc-cs-panel{
  background:var(--pbc-surface);
  border:var(--pbc-border-width) solid var(--pbc-border);
  border-radius:var(--pbc-radius-chip);
  box-shadow:var(--pbc-shadow-popover);
}

/* ── Right-hand actions ───────────────────────────────────────────────
   .header-nav is KEPT on the <nav> because style.css hangs the bell and
   account dropdown panels off `.header-nav .notifications` / `.profile`. */
body.pbc-shell #header .header-nav{margin-inline-start:auto;flex:none}
body.pbc-shell #header .header-nav > ul{
  display:flex;align-items:center;gap:var(--pbc-space-1);
  margin:0;padding:0;list-style:none;
}
body.pbc-shell #header .header-nav .nav-link,
body.pbc-shell #header .header-nav .nav-icon{
  display:grid;place-items:center;
  width:38px;height:38px;
  border-radius:var(--pbc-radius-sm);
  color:var(--pbc-ink-muted);
  font-size:17px;
  background:transparent;border:none;
  padding:0;
}
body.pbc-shell #header .header-nav .nav-link:hover,
body.pbc-shell #header .header-nav .nav-icon:hover{
  background:var(--pbc-surface-hover);
  color:var(--pbc-brand-600);
}
body.pbc-shell #header .header-nav .nav-link:focus-visible{
  outline:none;box-shadow:var(--pbc-focus-ring);
}
/* The bell's unread badge.
   Owner, 2026-08-02: this circle must be the SAME red as the dashboard's
   Overdue/Critical tiles — so it moved off --pbc-danger-600 (#B01818) onto
   --pbc-danger-alert (#DC3545). White on it is 4.53:1, which clears the 4.5:1
   that this 10.5px bold count needs as NORMAL text (it is far below the
   18.66px-bold large-text threshold) — but only just, so do NOT lighten this
   red further while white sits on it. The circle itself reads against both
   navbars: 4.53:1 on white, 3.49:1 on the dark #1a2238, over the 3:1 graphics bar. */
body.pbc-shell #header .pbc-bell-badge{
  background:var(--pbc-danger-alert) !important;
  color:var(--pbc-ink-on-brand);
  font-size:10.5px;font-weight:var(--pbc-weight-bold);
  border-radius:var(--pbc-radius-pill);
}
/* ⚠⚠ THIS RULE USED TO FLIP THE COUNT TO NAVY IN DARK, AND MUST NOT AGAIN.
   That existed only because --pbc-danger-600 flips to a pale pink (#F2A3A3) in
   dark, where white would have been 1.99:1. --pbc-danger-alert is a FIXED value
   in both themes, so the pink never appears — and navy on #DC3545 is 3.85:1,
   which would FAIL. The count stays white in dark; kept as an explicit rule
   rather than deleted so the trap stays documented. */
body.dark-mode.pbc-shell #header .pbc-bell-badge{color:var(--pbc-ink-on-brand)}

/* The account chip — avatar + username, in a pill. */
body.pbc-shell #header .header-nav .nav-profile.pbc-top__user{
  display:flex;align-items:center;gap:var(--pbc-space-2-5);
  width:auto;height:auto;
  padding:var(--pbc-space-1);
  padding-inline-end:var(--pbc-space-3);
  border:var(--pbc-border-width) solid var(--pbc-border);
  border-radius:var(--pbc-radius-pill);
  margin-inline-start:var(--pbc-space-2);
  color:var(--pbc-ink-heading);
}
body.pbc-shell #header .header-nav .nav-profile.pbc-top__user:hover{
  background:var(--pbc-surface-hover);
  border-color:var(--pbc-border-strong);
  color:var(--pbc-ink-heading);
}
body.pbc-shell .pbc-top__av{
  width:30px;height:30px;flex:none;
  border-radius:var(--pbc-radius-pill);
  background:var(--pbc-brand-600);
  color:var(--pbc-ink-on-brand);       /* 6.73:1 — brand-600 is the approved
                                          solid fill; steel would be 3.91:1 */
  display:grid;place-items:center;overflow:hidden;
  font-size:var(--pbc-text-xs);
  font-weight:var(--pbc-weight-bold);
  letter-spacing:.02em;
}
body.pbc-shell .pbc-top__av img{width:100%;height:100%;object-fit:cover;display:block}
body.pbc-shell .pbc-top__uname{
  font-size:var(--pbc-text-sm);
  font-weight:var(--pbc-weight-semibold);
  color:var(--pbc-ink-heading);
  white-space:nowrap;
  max-width:180px;overflow:hidden;text-overflow:ellipsis;
}
body.pbc-shell .pbc-top__caret{font-size:11px;color:var(--pbc-ink-faint);flex:none}
/* The language switcher keeps its label next to the globe. */
body.pbc-shell #header .header-nav .dropdown-toggle.pbc-top__lang{
  width:auto;padding-inline:var(--pbc-space-2-5);gap:var(--pbc-space-1-5);
  display:flex;align-items:center;
  font-size:var(--pbc-text-sm);font-weight:var(--pbc-weight-semibold);
}
body.pbc-shell #header .header-nav .dropdown-toggle::after{display:none}

/* ── The two dropdown panels ──────────────────────────────────────────
   Surfaces, borders and corners only. The notification LIST's internals are
   deliberately untouched in this step (owner, 2026-07-29) — restructuring
   them is a follow-on slice. */
body.pbc-shell #header .dropdown-menu{
  background:var(--pbc-surface);
  border:var(--pbc-border-width) solid var(--pbc-border);
  border-radius:var(--pbc-radius-chip);
  box-shadow:var(--pbc-shadow-popover);
  padding-block:var(--pbc-space-1-5);
  color:var(--pbc-ink-body);
}
body.pbc-shell #header .dropdown-menu .dropdown-item{
  display:flex;align-items:center;gap:var(--pbc-space-2-5);
  border-radius:var(--pbc-radius-sm);
  font-size:var(--pbc-text-base);
  color:var(--pbc-ink-body);
  padding-block:var(--pbc-space-2);
  padding-inline:var(--pbc-space-3);
  width:auto;margin-inline:var(--pbc-space-1-5);
}
body.pbc-shell #header .dropdown-menu .dropdown-item:hover{
  background:var(--pbc-surface-hover);
  color:var(--pbc-ink-heading);
}
body.pbc-shell #header .dropdown-menu .dropdown-item i{font-size:16px}

/* ── Content + footer offsets ─────────────────────────────────────────
   #main and #footer live in the 107 individual page files and are NOT
   edited — the shell is positioned around them. */
body.pbc-shell #main.main{
  /* narrows style.css's blanket `transition:all 0.3s` to the one property
     that actually moves — see the notes at the top of this section */
  transition:margin-inline-start var(--pbc-duration-base) var(--pbc-ease-standard);
  margin-top:var(--pbc-topbar-h);
  margin-inline-start:var(--pbc-sidebar-w);
  margin-inline-end:0;
  padding:var(--pbc-page-pad-y) var(--pbc-page-pad-x);
  background:var(--pbc-bg);
}
body.pbc-shell #footer.footer{
  transition:margin-inline-start var(--pbc-duration-base) var(--pbc-ease-standard);
  margin-inline-start:var(--pbc-sidebar-w);
  margin-inline-end:0;
  background:transparent;
  border-top:var(--pbc-border-width) solid var(--pbc-border);
  padding:var(--pbc-space-5) var(--pbc-page-pad-x);
  font-size:var(--pbc-text-sm);
  /* ink-MUTED, not ink-faint: at this 13.5px size ink-faint lands at 3.43:1 on
     the light canvas, under AA. Same call as the search placeholder. */
  color:var(--pbc-ink-muted);
}
/* style.css hardcodes `.footer .copyright{color:#012970}` — the legacy navy.
   On the dark canvas that is 1.34:1, i.e. invisible. It was never noticed
   because dark mode has been dead app-wide; fixing dark mode is what exposed
   it. Inheriting the footer's own token colour clears both themes. */
body.pbc-shell #footer.footer .copyright{color:inherit}

/* ── Narrow windows (<1200px) ─────────────────────────────────────────
   The sidebar goes off-canvas and .toggle-sidebar means SHOWN rather than
   collapsed — the inverted meaning is inherited from the legacy shell and
   is why the desktop rail rules above are inside a min-width query. */
@media (max-width:1199px){
  /* The sidebar overlays the page instead of reserving space for itself, so
     the bar, the content and the footer all run edge to edge. */
  body.pbc-shell #header.header,
  body.pbc-shell.toggle-sidebar #header.header{inset-inline-start:0}
  body.pbc-shell #main.main,
  body.pbc-shell #footer.footer,
  body.pbc-shell.toggle-sidebar #main.main,
  body.pbc-shell.toggle-sidebar #footer.footer{margin-inline-start:0}

  body.pbc-shell #sidebar.sidebar,
  body.pbc-shell.toggle-sidebar #sidebar.sidebar{
    width:var(--pbc-sidebar-w);
    box-shadow:var(--pbc-shadow-lg);
  }
  body.pbc-shell #sidebar.sidebar{inset-inline-start:calc(-1 * var(--pbc-sidebar-w))}
  body.pbc-shell.toggle-sidebar #sidebar.sidebar{inset-inline-start:0}

  /* ⚠ responsive.css sets `#header.header{height:auto;flex-wrap:wrap}` below
     767px — built for the old 105px bar. Left alone it wrapped the whole
     actions cluster onto a SECOND LINE inside a bar that is only 62px tall,
     so the bell, dark mode, language and avatar were half cut off at 375px.
     One line, always; the organisation name truncates instead. */
  body.pbc-shell #header.header{flex-wrap:nowrap;height:var(--pbc-topbar-h)}

  /* The organisation moves into the bar, because the sidebar carrying it
     is now off-screen. */
  body.pbc-shell .pbc-top__org{display:flex}
  body.pbc-shell .pbc-top__title{display:none}

  /* Search collapses to the icon; main.js reveals it as a panel under the
     bar. `top` has to follow the new 62px bar, not style.css's 60px. */
  body.pbc-shell .search-bar{
    position:fixed;
    top:calc(var(--pbc-topbar-h) - 12px);
    inset-inline-start:0;inset-inline-end:0;
    max-width:none;
    padding:var(--pbc-space-4);
    background:var(--pbc-surface);
    border-bottom:var(--pbc-border-width) solid var(--pbc-border);
    box-shadow:var(--pbc-shadow-md);
    z-index:998;
    visibility:hidden;opacity:0;
    transition:var(--pbc-duration-base) var(--pbc-ease-standard);
  }
  body.pbc-shell .search-bar.search-bar-show{
    top:var(--pbc-topbar-h);
    visibility:visible;opacity:1;
  }
  body.pbc-shell #pbcCaseSearchForm{width:100%}

  body.pbc-shell #main.main{padding:var(--pbc-space-6) var(--pbc-space-5)}
  body.pbc-shell #footer.footer{padding-inline:var(--pbc-space-5)}
}

/* Very narrow: the username label goes, the avatar stays. */
@media (max-width:600px){
  body.pbc-shell .pbc-top__uname,
  body.pbc-shell .pbc-top__caret{display:none}
  body.pbc-shell #header .header-nav .nav-profile.pbc-top__user{
    padding-inline-end:var(--pbc-space-1);
  }
  body.pbc-shell #header.header{padding-inline:var(--pbc-space-3)}
}

/* ==========================================================
   CHAT GROUPS — the group list          (§K K-4.6b, 2026-07-30)
   ----------------------------------------------------------
   The screen is built on the ALREADY-APPROVED case-list
   components: .pbc-card + .pbc-table--zebra + .pbc-table__group
   for the two ownership sections. Only the pieces that did not
   exist yet live here.

   ⚠ The owner's rule from the case list applies: a list you WORK
   from gets ALIGNED COLUMNS, not row-cards. Do not "restore"
   this to a card grid.
   ========================================================== */

/* A group's face, and a person's face in a stack — the same material as
   the chat conversation tiles, so one group wears one face everywhere.
   ⚠ background-COLOR, never the `background` shorthand: the shorthand would
   wipe the matte overlay that the next declaration puts on (the trap that
   already cost two button hovers in §14.267). The base .pbc-avatar fills
   with a gradient, so background-image has to be overridden explicitly. */
.pbc-avatar--group{
  border-radius:var(--pbc-radius-chip);
  background-color:var(--pbc-brand-800);
  background-image:var(--pbc-btn-matte);
  box-shadow:var(--pbc-btn-matte-lip);
}
.pbc-avatar--matte{
  background-color:var(--pbc-brand-600);
  background-image:var(--pbc-btn-matte);
  box-shadow:var(--pbc-btn-matte-lip);
}
/* NEVER on a face that carries a photo — the overlay would just darken the
   picture. The blade decides; this is the belt to that braces. */
.pbc-avatar--group:has(img),
.pbc-avatar--matte:has(img){background-image:none;box-shadow:none}

/* the group cell: face + name over description */
.pbc-gname{display:flex;align-items:center;gap:var(--pbc-space-3);min-width:0}
.pbc-gname__text{min-width:0}

/* ⚠⚠ THE LONG SELECTOR IS DELIBERATE — SEVENTH TIME THE LEGACY RE-SKIN HAS
   OUT-SPECIFIED THE COMPONENT LAYER. The group name is an <a>, and
   `pbc-theme.css` paints every anchor it is not excluded from. A plain
   `.pbc-glink` is (0,1,0) and loses; this is (0,3,3) and wins WITHOUT
   editing the shared legacy file. Identical shape to the case list's
   `a.pbc-ccase__t` fix — see that block. Do not "simplify" it. */
.pbc-scope .pbc-table--zebra tbody td a.pbc-glink,
.pbc-glink{
  font-weight:var(--pbc-weight-semibold);
  color:var(--pbc-ink-heading);
  display:block;text-decoration:none;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
/* ⚠ HOVER USES --pbc-brand-accent, NOT --pbc-brand-700. brand-700 is a DARK
   blue: it reads 9.36:1 on the light canvas and 1.58 / 1.44 / 1.14 on the dark
   surface, stripe and hover row — effectively invisible. brand-accent is the
   token that FLIPS per theme (brand-600 light, brand-300 dark), which is the
   same fix §14.267 applied to chat's icons.
   ⚠ The case list has the identical hover written with brand-700
   (`a.pbc-ccase__t:hover`, line ~1656) and therefore the same dark-mode defect.
   It is a DIFFERENT screen, so it is logged as a carry-over rather than
   silently changed here — see STATE.md. */
.pbc-scope .pbc-table--zebra tbody td a.pbc-glink:hover{
  color:var(--pbc-brand-accent);text-decoration:underline;
}
.pbc-gname__desc{
  font-size:var(--pbc-text-sm);color:var(--pbc-ink-muted);
  display:block;margin-top:2px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}

/* the members cell: overlapping faces + the count */
.pbc-facerow{display:flex;align-items:center;gap:var(--pbc-space-3)}
.pbc-facerow__n{
  font-size:var(--pbc-text-sm);color:var(--pbc-ink-muted);
  font-variant-numeric:tabular-nums;
}

/* the member list inside the Manage modal. Rendered by JS, so these class
   names are load-bearing — grep `pbc-mrow` in the blade before renaming. */
.pbc-mrow{
  display:flex;align-items:center;gap:var(--pbc-space-3);
  padding:var(--pbc-space-3) 0;
  border-top:var(--pbc-border-width) solid var(--pbc-border-subtle);
}
.pbc-mrow:first-child{border-top:none}
.pbc-mrow--head{
  border-top:none;padding-block:0 var(--pbc-space-2);
  font-size:var(--pbc-text-xs);font-weight:var(--pbc-weight-bold);
  letter-spacing:var(--pbc-tracking-caps);text-transform:uppercase;
  color:var(--pbc-ink-muted);
}
.pbc-mrow__name{flex:1;min-width:0;display:flex;align-items:center;gap:var(--pbc-space-3)}
.pbc-mrow__col{width:72px;text-align:center;flex:none}
.pbc-mrow__act{width:44px;text-align:end;flex:none}

/* the "add members" row inside the Manage modal: picker + button on one line.
   ⚠ NOT .pbc-cols — that is the dashboard's 7fr/5fr GRID, which would give the
   Add button five twelfths of the modal. And nothing here may flex-grow past
   the button (trap: an auto margin does not reserve space during free-space
   distribution), so the picker grows and the button stays its natural width. */
.pbc-addrow{display:flex;align-items:flex-start;gap:var(--pbc-space-3);flex-wrap:wrap}
.pbc-addrow__field{flex:1 1 220px;min-width:0}
/* the save-permissions button, pushed to the modal's trailing edge */
.pbc-mactions{display:flex;justify-content:flex-end;margin-top:var(--pbc-space-4)}

/* ==========================================================
   NOTIFICATION PANEL — §K K-4.OVERLAYS (2026-08-01)
   ==========================================================
   The bell dropdown, and the "All notifications" modal, which reuses the
   same row. Owner's pick: C1 + the rail from C2 — an unread row gets BOTH
   the pale brand tint AND the blue line on its leading edge.

   ⚠ IT IS A BOOTSTRAP DROPDOWN. Bootstrap toggles .dropdown-menu between
   display:none and display:block via .show. A bare `.pbc-notif{display:flex}`
   would out-rank the `none` and leave the panel PERMANENTLY OPEN, so the
   flex is applied only on .show.
   ⚠ K-4.5's `body.pbc-shell #header .dropdown-menu` rule carries an ID, so
   it out-specifies a plain class. These selectors repeat that prefix to win
   back the padding — that is why they look over-qualified.
   ⚠ The rows are built by JAVASCRIPT in two places (notifications-bell.blade
   .php: renderNotifications + allRowHtml). Converting only one leaves legacy
   rows appearing at runtime. */
.dropdown-menu.pbc-notif,
body.pbc-shell #header .dropdown-menu.pbc-notif{
  width:380px;max-width:calc(100vw - 24px);
  padding:0;
  max-height:480px;
  overflow:hidden;
  background:var(--pbc-surface);
  border:var(--pbc-border-width) solid var(--pbc-border);
  border-radius:var(--pbc-radius-card);
  box-shadow:var(--pbc-shadow-popover);
}
.dropdown-menu.pbc-notif.show{display:flex;flex-direction:column}

.pbc-notif__head{
  flex:0 0 auto;
  display:flex;align-items:center;justify-content:space-between;
  gap:var(--pbc-space-3);
  padding:var(--pbc-space-3) var(--pbc-space-5);
  border-bottom:var(--pbc-border-width) solid var(--pbc-border-subtle);
  background:var(--pbc-surface-soft);
}
.pbc-notif__title{
  font-family:var(--pbc-font-heading);
  font-weight:var(--pbc-weight-heading);
  font-size:var(--pbc-text-base);
  color:var(--pbc-ink-heading);
}
.pbc-notif__count{
  font-family:var(--pbc-font-body);
  font-weight:var(--pbc-weight-normal);
  font-size:var(--pbc-text-sm);
  color:var(--pbc-ink-muted);
}
.pbc-notif__tools{display:flex;align-items:center;gap:var(--pbc-space-3)}
.pbc-notif__link{
  font-size:var(--pbc-text-sm);
  color:var(--pbc-brand-accent);
  text-decoration:none;
  font-weight:var(--pbc-weight-medium);
  background:none;border:none;padding:0;cursor:pointer;
}
.pbc-notif__link:hover{text-decoration:underline;color:var(--pbc-brand-accent)}
.pbc-notif__gear{
  width:28px;height:28px;
  border-radius:var(--pbc-radius-xs);
  border:none;background:none;cursor:pointer;
  color:var(--pbc-ink-faint);
  display:inline-flex;align-items:center;justify-content:center;
  transition:background-color var(--pbc-transition),color var(--pbc-transition);
}
.pbc-notif__gear:hover{background:var(--pbc-surface-hover);color:var(--pbc-ink-heading)}
.pbc-notif__list{flex:1 1 auto;min-height:0;overflow-y:auto}
.pbc-notif__foot{
  flex:0 0 auto;
  text-align:center;
  padding:var(--pbc-space-2-5);
  border-top:var(--pbc-border-width) solid var(--pbc-border-subtle);
  background:var(--pbc-surface-soft);
}
.pbc-notif__empty{
  text-align:center;
  padding:var(--pbc-space-10) var(--pbc-space-5);
  color:var(--pbc-ink-faint);
  font-size:var(--pbc-text-sm);
}
.pbc-notif__empty i{font-size:26px;display:block;margin-bottom:var(--pbc-space-2)}
.pbc-notif__loading{
  text-align:center;
  padding:var(--pbc-space-6) var(--pbc-space-5);
  color:var(--pbc-ink-faint);
  font-size:var(--pbc-text-sm);
}

/* ── one row ──────────────────────────────────────────────
   ⚠ display:block on the three text lines. The rows are built from <span>s
   in JS; left inline they run onto one line, the message never ellipsises
   (an inline box ignores its flex parent's min-width:0) and the row pushes
   past the panel's overflow:hidden edge. Every static check passed on that
   — it was only found by looking at it. */
.pbc-notif__row{
  display:flex;align-items:flex-start;
  gap:var(--pbc-space-3);
  padding:var(--pbc-space-3) var(--pbc-space-5);
  padding-inline-start:calc(var(--pbc-space-5) - 3px);
  border-inline-start:3px solid transparent;
  border-bottom:var(--pbc-border-width) solid var(--pbc-border-subtle);
  text-decoration:none;color:inherit;white-space:normal;
  transition:background-color var(--pbc-transition);
}
.pbc-notif__row:last-child{border-bottom:none}
.pbc-notif__row:hover{background:var(--pbc-row-hover)}
/* owner's C1 + C2 rail: the tint AND the line.
   ⚠ brand-ACCENT, not brand-600. brand-600 is a mid navy: 6.73:1 on the white
   panel but only 2.20:1 on the dark one — the "blue line" the owner asked for
   would have been invisible in dark mode, which is the one thing it exists to
   not be. brand-accent flips with the theme (6.73:1 / 7.16:1) and the token
   file names this exact use: "brand colour used as TEXT or a 1px accent". */
.pbc-notif__row.is-unread{
  background:var(--pbc-brand-100);
  border-inline-start-color:var(--pbc-brand-accent);
}
.pbc-notif__row.is-unread:hover{background:var(--pbc-row-hover)}
.pbc-notif__body{flex:1 1 auto;min-width:0}
.pbc-notif__t{
  display:block;
  font-size:var(--pbc-text-sm);
  font-weight:var(--pbc-weight-semibold);
  color:var(--pbc-ink-heading);
  line-height:var(--pbc-leading-snug);
}
.pbc-notif__m{
  display:block;
  font-size:var(--pbc-text-sm);
  color:var(--pbc-ink-muted);
  line-height:var(--pbc-leading-snug);
  margin-top:1px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
/* ⚠ ink-MUTED, not ink-faint. --pbc-ink-faint is 4.33:1 on the light hover
   shade and 3.28:1 on the dark one (the documented row-shade trap). The
   timestamp is made quieter than the message by SIZE, not colour. */
.pbc-notif__when{
  display:block;
  font-size:var(--pbc-text-xs);
  color:var(--pbc-ink-muted);
  margin-top:var(--pbc-space-1);
}
.pbc-notif__ico{
  flex:none;
  display:inline-flex;align-items:center;justify-content:center;
  font-size:18px;line-height:1;margin-top:2px;
}
/* ⚠ same reason as the rail: the dot sits ON the unread tint, where
   brand-600 measures 1.55:1 in dark — effectively gone. */
.pbc-notif__dot{
  flex:none;
  width:8px;height:8px;
  border-radius:var(--pbc-radius-pill);
  background:var(--pbc-brand-accent);
  margin-top:6px;
}
/* the icon's meaning colour — one class per notification kind */
.pbc-ntone--brand  {color:var(--pbc-brand-accent)}
.pbc-ntone--success{color:var(--pbc-success-600)}
.pbc-ntone--warning{color:var(--pbc-warning-600)}
.pbc-ntone--danger {color:var(--pbc-danger-600)}
.pbc-ntone--info   {color:var(--pbc-info-600)}
.pbc-ntone--neutral{color:var(--pbc-neutral-600)}

/* the same rows inside the "All notifications" modal, which is wider and
   scrolls on its own — so the panel chrome above does not apply there */
.pbc-notif-modal-list .pbc-notif__row{padding-block:var(--pbc-space-4)}

/* ==========================================================
   MEETING "STARTING SOON" POP-UP — §K K-4.OVERLAYS (2026-08-01)
   ==========================================================
   Owner's D2: navy is reserved for anything CALL-related, so this calendar
   reminder stays an ordinary light card and goes dark with the app.
   ⚠ It used to carry an inline <style> in its own blade using `--bs-body-bg`
   fallbacks and a raw rgba border, so it never followed the theme — in dark
   mode it rendered as a white slab.
   ⚠ z-index 1085: above modals (1050) but BELOW the call UI, deliberately.
   An unsolicited reminder must never sit on top of a ringing call. */
.pbc-meeting-popup{
  position:fixed;
  top:50%;left:50%;
  transform:translate(-50%,-50%);
  z-index:1085;
  width:calc(100% - 2rem);
  max-width:380px;
}
.pbc-meeting-popup-card{
  position:relative;
  background:var(--pbc-surface);
  color:var(--pbc-ink-body);
  border:var(--pbc-border-width) solid var(--pbc-border);
  border-radius:var(--pbc-radius-card);
  box-shadow:var(--pbc-shadow-lg);
  padding:var(--pbc-card-pad);
}
.pbc-meeting-popup-close{
  position:absolute;
  top:var(--pbc-space-3);
  inset-inline-end:var(--pbc-space-3);
}
.pbc-meeting-popup__kicker{
  display:flex;align-items:center;gap:var(--pbc-space-1-5);
  font-size:var(--pbc-text-xs);
  letter-spacing:var(--pbc-tracking-caps);
  text-transform:uppercase;
  font-weight:var(--pbc-weight-semibold);
  color:var(--pbc-ink-faint);
  margin-bottom:var(--pbc-space-2);
}
.pbc-meeting-popup__t{
  font-family:var(--pbc-font-heading);
  font-size:var(--pbc-text-lg);
  font-weight:var(--pbc-weight-heading);
  color:var(--pbc-ink-heading);
  line-height:var(--pbc-leading-snug);
  margin-bottom:var(--pbc-space-1);
}
.pbc-meeting-popup__when{
  font-size:var(--pbc-text-sm);
  color:var(--pbc-ink-muted);
  margin-bottom:var(--pbc-space-5);
}
.pbc-meeting-popup__acts{
  display:flex;justify-content:flex-end;gap:var(--pbc-space-2);
}

/* ==========================================================
   NOTIFICATION-SETTINGS ROW — §K K-4.OVERLAYS (2026-08-01)
   ==========================================================
   One switchable preference. Replaces a stack of Bootstrap utilities
   (d-flex justify-content-between py-2 border-bottom + text-muted small). */
.pbc-prefrow{
  display:flex;align-items:flex-start;justify-content:space-between;
  gap:var(--pbc-space-4);
  padding-block:var(--pbc-space-3);
  border-bottom:var(--pbc-border-width) solid var(--pbc-border-subtle);
}
.pbc-prefrow--last{border-bottom:none;padding-bottom:0}
.pbc-prefrow__text{min-width:0}
.pbc-prefrow__t{
  display:block;
  font-size:var(--pbc-text-base);
  font-weight:var(--pbc-weight-semibold);
  color:var(--pbc-ink-heading);
}
.pbc-prefrow__d{
  display:block;
  font-size:var(--pbc-text-sm);
  color:var(--pbc-ink-muted);
  line-height:var(--pbc-leading-snug);
  margin-top:2px;
}
.pbc-prefrow__lock{
  display:flex;align-items:center;gap:var(--pbc-space-2);
  flex:none;
}

/* ==========================================================
   §K K-4.11 — THE END-USER BATCH (2026-08-02)
   ----------------------------------------------------------
   Ported verbatim from PBC Mockup/enduser-batch-proposed.css
   after the owner picked A3 · B2 · C1 · D3 · E2 from
   PBC Mockup/enduser-batch-options.html.

   E2 (onboarding) needed NO new CSS — it reuses .pbc-wizbar,
   the tracker chosen for the setup wizard in K-4.9.

   DELIBERATELY NOT PORTED (rejected options, kept only in the
   gallery as the decision record): A2's .pbc-card__head--filters,
   C2's .pbc-stat--rule, C3's .pbc-stat--fill and its dark block.

   Consumers: My Tasks · Work timer · Audit trail · Organization
   Users · Subject · Reports · Settings · Welcome.
   ========================================================== */

/* ---------- A3 · the filter tray ------------------------- */
/* A shaded control panel above the table card, so filters read
   as controls rather than as content. */
.pbc-filtertray{
  display:flex;align-items:flex-end;flex-wrap:wrap;
  gap:var(--pbc-space-3);
  padding:var(--pbc-space-4);
  background:var(--pbc-surface-soft);
  border:var(--pbc-border-width) solid var(--pbc-border);
  border-radius:var(--pbc-radius-card);
  margin-block-end:var(--pbc-space-6);
}
/* ⚠ NOTHING IN THIS ROW MAY FLEX-GROW. The actions are pushed out with
   margin-inline-start:auto, and an auto margin does not reserve space while
   flex distributes free space — a growing control swallows exactly the room
   the buttons need and orphans them onto their own line. That cost three
   passes on .pbc-casefilter (§14.265); it is not re-learned here. */
.pbc-filtertray .pbc-field{flex:0 1 190px;min-width:160px;max-width:260px}  /* K-4.82: was 170/150/240 — "All permitted activities" clipped at 170 */
/* K-4.82: a tray inside a .pbc-stack already gets the stack's 24px gap */
.pbc-stack>.pbc-filtertray{margin-block-end:0}
.pbc-filtertray .pbc-select,
.pbc-filtertray .pbc-input{width:100%}
.pbc-filtertray__acts{display:flex;gap:var(--pbc-space-2);margin-inline-start:auto}
/* K-4.82 (§14.374, owner 2026-08-23): a hint paragraph INSIDE a tray field made that
   field taller, and with align-items:flex-end its control rode above its neighbours
   (Sent emails / Print log, the Department filter). In a tray, hints go on a footnote
   line under the whole row instead — the control row stays one line. */
.pbc-filtertray .pbc-field__hint{display:none}
.pbc-filtertray__note{
  flex-basis:100%;margin:0;
  font-size:var(--pbc-text-sm);color:var(--pbc-ink-muted);
}
@media (max-width:820px){
  .pbc-filtertray__acts{margin-inline-start:0}
  .pbc-filtertray .pbc-field{flex:1 1 150px;max-width:none}
}

/* ---------- B2 · row actions: primary + overflow --------- */
/* ⚠ NO :hover REVEAL. The owner rejected hover-revealed tools outright in
   chat (§14.271 add. 3, "too annoying"). The menu opens on CLICK only. */
.pbc-rowacts{
  display:inline-flex;align-items:center;gap:var(--pbc-space-2);
  justify-content:flex-end;
}
.pbc-rowacts__more{position:relative}
/* The panel is the EXISTING .pbc-menu — no second dropdown component is
   invented. This is .pbc-menu's first consumer in the app, so it was rendered
   and eyeballed in the gallery before shipping (the .pbc-steps lesson: a
   component with no consumer has never been seen, and hid a real defect for
   two weeks). */
/* ⚠⚠ FIXED, NOT ABSOLUTE — and that is a bug fix, not a preference
   (K-4.11 add. 1, owner-reported 2026-08-02).
   This menu lives inside `.pbc-table-wrap`, which carries `overflow-x:auto` so
   a wide table scrolls sideways instead of breaking the page. Per spec, setting
   ONE overflow axis to anything but `visible` makes the OTHER axis clip too —
   so an absolutely-positioned menu was cut off at the bottom of the wrap, and
   on a single-row table there was nowhere for it to render at all. The owner
   saw it as "cut off … I have to scroll down into my task list to see them."
   A fixed element is laid out against the viewport, so no ancestor's overflow
   can clip it. pbc-rowmenu.js sets top/left on open and flips it above the
   trigger when there is no room below.
   ⚠ Do NOT "fix" this by putting overflow:visible on .pbc-table-wrap — that is
   what gives wide tables their horizontal scroll.
   z-index 1000 clears the sidebar (996) and header (997) and stays under
   Bootstrap's modal layer (1050+), so a dropdown never covers a dialog. */
.pbc-rowacts__menu{
  position:fixed;
  z-index:1000;
  display:none;
}
.pbc-rowacts__more.is-open .pbc-rowacts__menu{display:block}

/* ---------- C1 · a stat tile in its selected state ------- */
/* The tiles on My Tasks ARE the status filter. Previously each carried an
   inline 2px hex border written per tile.
   ⚠ The ring is an INSET BOX-SHADOW, not a border: a border would change the
   tile's box and shift every sibling by a pixel when you clicked it. Proven:
   all six tiles measure 116px selected and unselected alike. */
.pbc-stat--pick.is-selected{
  background:var(--pbc-surface-soft);
  box-shadow:inset 0 0 0 2px var(--pbc-brand-accent);
}

/* ---------- D3 · pagination: range + numbers ------------- */
/* Consumers: Work timer, Audit trail. The case list needs this too the day it
   finally gets real pagination (it has never had any — ->get()). */
.pbc-pager{
  display:flex;align-items:center;gap:var(--pbc-space-3);flex-wrap:wrap;
  padding-block-start:var(--pbc-space-4);
}
.pbc-pager__range{
  font-size:var(--pbc-text-sm);color:var(--pbc-ink-muted);white-space:nowrap;
}
.pbc-pager__list{
  display:flex;align-items:center;gap:var(--pbc-space-1);
  list-style:none;margin:0;padding:0;
  margin-inline-start:auto;
}
.pbc-pager__item{
  display:inline-flex;align-items:center;justify-content:center;
  min-width:var(--pbc-control-h-sm);height:var(--pbc-control-h-sm);
  padding-inline:var(--pbc-space-2);
  border:var(--pbc-border-width) solid var(--pbc-border);
  border-radius:var(--pbc-radius-sm);
  background:var(--pbc-surface);
  color:var(--pbc-ink-body);
  font-family:inherit;font-size:var(--pbc-text-sm);font-weight:var(--pbc-weight-semibold);
  font-variant-numeric:tabular-nums;
  text-decoration:none;cursor:pointer;
  transition:background-color var(--pbc-transition),border-color var(--pbc-transition);
}
.pbc-pager__item:hover{background:var(--pbc-surface-hover);border-color:var(--pbc-border-strong)}
.pbc-pager__item:focus-visible{outline:none;box-shadow:var(--pbc-focus-ring)}
.pbc-pager__item.is-current{
  background:var(--pbc-brand-600);
  border-color:var(--pbc-brand-600);
  color:var(--pbc-ink-on-brand);
  cursor:default;
}
/* ⚠⚠ DARK: brand-600 CANNOT mark the current page here. Measured from this
   project's own token file: the white number on it stays at 6.73:1 — so a
   text-only contrast check PASSES — but the FILL, which is the entire "you are
   here" signal, drops to 2.20:1 against the sibling buttons. Legible and yet
   invisible as a marker. In dark the fill becomes brand-accent (7.16:1 on a
   sibling) with brand-950 ink on it (7.81:1).
   This is the fourth time brand-600 has had to be swapped out on a dark
   surface — the unread rail, the chat tools, the case-list title hover, now
   this. brand-600 is a LIGHT-MODE FILL, never a marker on dark. */
body.dark .pbc-pager__item.is-current,
body.dark-mode .pbc-pager__item.is-current{
  background:var(--pbc-brand-accent);
  border-color:var(--pbc-brand-accent);
  color:var(--pbc-brand-950);
}
.pbc-pager__item.is-disabled{
  color:var(--pbc-ink-faint);
  background:var(--pbc-surface-soft);
  cursor:default;
}
.pbc-pager__gap{
  display:inline-flex;align-items:center;justify-content:center;
  min-width:var(--pbc-control-h-sm);height:var(--pbc-control-h-sm);
  color:var(--pbc-ink-faint);
}
@media (max-width:640px){
  .pbc-pager__list{margin-inline-start:0}
}

/* ---------- a striped row that is NOT click-through ------ */
/* .pbc-crow is what the zebra rule keys on, but it also sets cursor:pointer
   because on the case list the whole row IS a link (data-href + a row click
   handler). My Tasks rows are not clickable — they carry their own buttons —
   so a pointer there promises something that does not happen.
   Additive modifier: striping without the promise. No existing screen changes. */
.pbc-table--zebra tbody tr.pbc-crow--static{cursor:default}

/* ---------- the password-strength meter (onboarding) ----- */
/* The Welcome screen's meter used to set four raw hex colours from JavaScript
   (#dc3545 / #fd7e14 / #ffc107 / #28a745 — Bootstrap 4 values that appear
   nowhere else in this app). The JS now toggles a class and the colour lives
   here, which is the only way a token can reach it.
   danger-500 / warning-500 / success-500 are used because none of the three
   flips in dark mode — the same reason the call buttons and the wizard's
   done-marker are pinned to -500s. A -600 would print a pastel bar in dark. */
.pbc-pwbar{
  height:6px;background:var(--pbc-neutral-100);
  border-radius:var(--pbc-radius-pill);overflow:hidden;
  margin-block-start:var(--pbc-space-2);
}
.pbc-pwbar__fill{
  height:100%;width:0;border-radius:var(--pbc-radius-pill);
  transition:width var(--pbc-duration-base) var(--pbc-ease-out),
             background-color var(--pbc-duration-base) var(--pbc-ease-out);
}
.pbc-pwbar__fill.is-weak  {background:var(--pbc-danger-500)}
/* ⚠ THE MIDDLE TWO ARE warning-600, NOT warning-500 like their siblings, and
   that asymmetry is measured rather than sloppy. warning-500 (#C08A2B) is only
   2.83:1 against the LIGHT track — below the 3:1 a meaningful graphic needs.
   warning-600 flips (#7F5A14 light → #E8B455 dark), which is normally the trap
   that ruins a fill... except the TRACK flips with it (neutral-100 #F4F7FB →
   #142A43), so the pair moves together: 5.79:1 light, 7.69:1 dark. The flip
   works FOR this one because both sides of the pairing are themed. */
.pbc-pwbar__fill.is-fair  {background:var(--pbc-warning-600)}
.pbc-pwbar__fill.is-good  {background:var(--pbc-warning-600)}
.pbc-pwbar__fill.is-strong{background:var(--pbc-success-500)}
.pbc-pwlabel{font-size:var(--pbc-text-sm);margin-block-start:var(--pbc-space-1)}
.pbc-pwlabel.is-weak  {color:var(--pbc-danger-600)}
.pbc-pwlabel.is-fair,
.pbc-pwlabel.is-good  {color:var(--pbc-warning-600)}
.pbc-pwlabel.is-strong{color:var(--pbc-success-600)}

/* ---------- the onboarding column + password field ------- */
/* Welcome is a single centred column — the only screen in the app that is not
   a full-width work surface. It is the first thing a new person ever sees. */
.pbc-onboard{max-width:620px;margin-inline:auto}
/* the show/hide-password control sits inside the input's box */
.pbc-pwfield{position:relative;display:block}
.pbc-pwfield .pbc-input{padding-inline-end:var(--pbc-control-h)}
.pbc-pwfield__toggle{
  position:absolute;inset-inline-end:0;bottom:0;
  width:var(--pbc-control-h);height:var(--pbc-control-h);
  display:grid;place-content:center;
  border:none;background:none;cursor:pointer;
  color:var(--pbc-ink-muted);
  border-radius:var(--pbc-radius-sm);
}
.pbc-pwfield__toggle:hover{color:var(--pbc-ink-heading)}
.pbc-pwfield__toggle:focus-visible{outline:none;box-shadow:var(--pbc-focus-ring)}

/* ---------- .pbc-optcard as a SELECTABLE control --------- */
/* K-4.11 (2026-08-02). The Reports widget picker is the component's first
   consumer that is an actual <button>, so the browser's button defaults have
   to be reset the same way a.pbc-stat/button.pbc-stat already are: a button
   centres its text and does NOT inherit the page font. Without this the picker
   cards render centred in the browser's default UI font. */
button.pbc-optcard{
  font:inherit;text-align:start;width:100%;cursor:pointer;
}
button.pbc-optcard:focus-visible{outline:none;box-shadow:var(--pbc-focus-ring)}
/* selected — a ring, not a border, so nothing reflows on click (same reasoning
   as .pbc-stat--pick.is-selected) */
.pbc-optcard.is-selected{
  background:var(--pbc-surface-soft);
  box-shadow:inset 0 0 0 2px var(--pbc-brand-accent);
}
/* already added — present but not choosable */
.pbc-optcard.is-disabled{
  background:var(--pbc-surface-soft);
  cursor:default;
}
.pbc-optcard.is-disabled:hover{border-color:var(--pbc-border)}
/* the picker's leading glyph and its tick */
.pbc-optcard .ur-lib-check,
.pbc-optcard .pbc-lib-check{   /* K-4.78: the Superadmin org page's twin picker keeps its own hook names */
  width:40px;height:40px;flex:none;
  display:grid;place-content:center;
  border-radius:var(--pbc-radius-chip);
  background:var(--pbc-surface-soft);
  color:var(--pbc-brand-accent);
}
.pbc-optcard.is-selected .ur-lib-check,
.pbc-optcard.is-selected .pbc-lib-check{background:var(--pbc-surface)}
/* the "this one is chosen" tick, pinned to the card's end corner so it never
   pushes the title or description around when it appears.
   Three consumers: the Reports widget picker (.ur-lib-tick, K-4.11), its Superadmin
   twin on the organisation page (.pbc-lib-tick, K-4.78) and the New
   Case wizard's type cards (.case-type-check, K-4.13). Both are toggled by
   their page's JS with `d-none`, which is FUNCTIONAL here, not decorative. */
.pbc-optcard{position:relative}
.pbc-optcard .ur-lib-tick,
.pbc-optcard .pbc-lib-tick,
.pbc-optcard .case-type-check{
  position:absolute;
  top:var(--pbc-space-3);inset-inline-end:var(--pbc-space-3);
  color:var(--pbc-brand-accent);
  line-height:1;
}

/* ---------- priority chips, in their own colours --------- */
/* Owner, 2026-08-02, on the New Case wizard: "for these priorities it should be
   in the colours that it used to be in." The first pass made them neutral chips
   that filled brand when selected — the app's generic selection language — but
   priority IS meaning, so it earns colour (the standing rule is that colour only
   ever carries meaning, not that it is rationed).

   ⚠⚠ EVERY COLOUR HERE IS ONE HALF OF AN EXISTING .pbc-pill--* PAIR, and that is
   deliberate. `--pbc-warning-600` (#7F5A14) FLIPS to #E8B455 in dark, and
   `--pbc-danger-600` (#B01818) flips to #F2A3A3 — as a raw fill either would
   print a pastel chip. They are safe here because their partner tokens
   (`-100` tint and `-border`) flip WITH them, exactly as `.pbc-pill--warning`
   and `.pbc-pill--danger` already rely on app-wide. Do not substitute a -500.

   Unselected: the colour lives in the text and the border, so all four options
   are distinguishable at rest — the old btn-outline-* behaviour.
   Selected: the pill's own tint plus a 2px ring in the same hue. The ring is an
   inset box-shadow, not a border, so nothing reflows when you pick one.

   MEASURED, both themes, all four, both states: labels 5.15–7.81:1 and the
   selected ring 5.06–7.51:1 — every one clears its bar. The unselected
   BORDERS land at 1.26–2.02:1, which reads as a failure in isolation but is
   the app's standing hairline convention: the default `.pbc-catpill` border
   (`--pbc-border`) is itself 1.26:1, so Low matches it exactly and High and
   Critical are MORE visible than the chips shipped everywhere else. The
   control is identified by its coloured label, not by its hairline. Changing
   this would mean changing every bordered surface in the design system. */
/* ⚠⚠ NORMAL IS THE `info` FAMILY, NOT `brand` — MEASURED, NOT PREFERENCE.
   The first attempt used --pbc-brand-accent for Normal and --pbc-neutral-600
   for Low. In DARK MODE both tokens resolve to the SAME hex (#9FB7D1): ΔE 0.0,
   two of the four chips literally identical. `info` is this system's blue
   family (it is what .pbc-pill--info already uses) and separates them.
   Low is left on the PLAIN chip ink on purpose — it is the "nothing special"
   option, exactly as it was btn-outline-secondary before. Separation now:
   Low↔Normal ΔE 13.0 light / 14.7 dark, Normal↔High 70/76, High↔Critical 49/47 —
   and Low's selected state has no colour at all, so the two never read alike. */
.pbc-catpill--pri-low     {color:var(--pbc-ink-body);   border-color:var(--pbc-border)}
.pbc-catpill--pri-normal  {color:var(--pbc-info-600);   border-color:var(--pbc-info-border)}
.pbc-catpill--pri-high    {color:var(--pbc-warning-600);border-color:var(--pbc-warning-border)}
.pbc-catpill--pri-critical{color:var(--pbc-danger-600); border-color:var(--pbc-danger-border)}

/* These must out-rank `.pbc-catpill.is-active`, which fills brand and turns the
   label white. Same specificity (0,2,0) — they win on source order, which is
   why this block lives at the END of the file.
   Labels on their own selected tint measure 5.40–10.34:1 across both themes. */
.pbc-catpill--pri-low.is-active{
  background:var(--pbc-surface-soft); color:var(--pbc-ink-body);
  border-color:var(--pbc-border-strong); box-shadow:inset 0 0 0 2px var(--pbc-ink-muted);
}
.pbc-catpill--pri-normal.is-active{
  background:var(--pbc-info-100); color:var(--pbc-info-600);
  border-color:var(--pbc-info-border); box-shadow:inset 0 0 0 2px var(--pbc-info-600);
}
.pbc-catpill--pri-high.is-active{
  background:var(--pbc-warning-100); color:var(--pbc-warning-600);
  border-color:var(--pbc-warning-border); box-shadow:inset 0 0 0 2px var(--pbc-warning-600);
}
.pbc-catpill--pri-critical.is-active{
  background:var(--pbc-danger-100); color:var(--pbc-danger-600);
  border-color:var(--pbc-danger-border); box-shadow:inset 0 0 0 2px var(--pbc-danger-600);
}
/* hover must not repaint them brand either */
.pbc-catpill--pri-low.is-active:hover     {background:var(--pbc-surface-soft); border-color:var(--pbc-border-strong)}
.pbc-catpill--pri-normal.is-active:hover  {background:var(--pbc-info-100);     border-color:var(--pbc-info-border)}
.pbc-catpill--pri-high.is-active:hover    {background:var(--pbc-warning-100);  border-color:var(--pbc-warning-border)}
.pbc-catpill--pri-critical.is-active:hover{background:var(--pbc-danger-100);   border-color:var(--pbc-danger-border)}


/* ==========================================================
   ORGANISATION IDENTITY HEADER — the Superadmin org page
   ----------------------------------------------------------
   §K K-4.29 (§14.297). Ported from the approved gallery
   specimen (`superadmin-detail-options.html`, decision D-1
   option A) rather than re-derived — the gallery's `.g-hero`,
   `.g-orgmark` and `.g-loginlink` become these three rules.

   ⚠ The header itself is `.pbc-pagehead` with a modifier, NOT
   a new component. The only thing that differs from every
   other page head is that a 56px organisation mark sits beside
   the title, and a mark that tall reads wrong against
   `.pbc-pagehead`'s default `align-items:flex-start`.
   ========================================================== */
.pbc-pagehead--identity{align-items:center}

/* The organisation's mark. Two variants of the SAME box, so a
   customer with a logo and one without occupy identical space
   and the title never shifts: `.pbc-orgmark` draws initials,
   `.pbc-orglogo--lg` is the uploaded image at the same size.
   ⚠ Kept in step with `.pbc-orglogo` (40px, the list row) — the
   two screens show the same organisation and must agree on its
   shape; only the scale differs. */
.pbc-orgmark{
  width:56px;height:56px;flex:none;
  border-radius:var(--pbc-radius-sm);
  background:var(--pbc-brand-600);
  color:var(--pbc-ink-on-brand);
  display:grid;place-items:center;
  font-weight:var(--pbc-weight-bold);
  font-size:var(--pbc-text-lg);
  letter-spacing:var(--pbc-tracking-tight);
}
.pbc-orglogo--lg{width:56px;height:56px}

/* The org's branded end-user login link (H31). A quiet strip
   rather than a card: it is a thing you copy, not a thing you
   read. Sits between the header and the stat tiles.
   ⚠ `flex-wrap` matters — the URL is arbitrary length and the
   Copy button must stay reachable on a narrow window rather
   than being pushed off the end of the strip. */
.pbc-loginlink{
  display:flex;align-items:center;flex-wrap:wrap;
  gap:var(--pbc-space-2-5);
  padding:var(--pbc-space-3) var(--pbc-space-4);
  margin-block-end:var(--pbc-section-gap);
  background:var(--pbc-surface-soft);
  border:var(--pbc-border-width) solid var(--pbc-border);
  border-radius:var(--pbc-radius-chip);
  font-size:var(--pbc-text-sm);
  color:var(--pbc-ink-muted);
}
.pbc-loginlink code{color:var(--pbc-ink-heading);font-size:var(--pbc-text-sm)}

/* ==========================================================
   THE POP-UP MACHINERY — §14.297 / K-4.29, stage 1
   ----------------------------------------------------------
   Built from the owner's eight P- decisions (§14.295, gallery
   `PBC Mockup/popup-gallery-options.html`, 2026-08-08):
     P-1 A  a window's head is its TITLE ONLY, on our spacing
     P-2 A  Cancel + action both at the END, on a tinted strip
     P-3 A  ONE house "are you sure?" dialog for all 124 sites
     P-4 A  our own corner message, in the SAME corner
     P-7 B  a picker shows its picks as chips ABOVE the list
     P-8 B  four widths — sm 420 / md 560 / lg 760 / xl 1000

   ⚠ NOTHING HERE CONVERTS A CALL SITE. This stage only builds
   the machinery the later stages call. Every existing pop-up
   keeps working exactly as it does today.
   ========================================================== */

/* ----------------------------------------------------------
   P-8 B — THE FOURTH WIDTH.
   `.pbc-modal--xl` is for the standalone component; the
   `.pbc-dlg--*` set is for a BOOTSTRAP modal, applied to its
   `.modal-dialog`. Own class rather than Bootstrap's own
   `.modal-xl` (1140px) — the owner picked 1000, and styling
   `.modal-xl` itself would reach every unconverted modal.
   ---------------------------------------------------------- */
.pbc-modal--xl{max-width:var(--pbc-modal-w-xl)}
.modal-dialog.pbc-dlg--sm{max-width:var(--pbc-modal-w-sm)}
.modal-dialog.pbc-dlg--md{max-width:var(--pbc-modal-w)}
.modal-dialog.pbc-dlg--lg{max-width:var(--pbc-modal-w-lg)}
.modal-dialog.pbc-dlg--xl{max-width:var(--pbc-modal-w-xl)}

/* ----------------------------------------------------------
   P-1 A + P-2 A — THE HOUSE FRAME, on Bootstrap's machinery.
   ----------------------------------------------------------
   Extends the existing `.modal-content.pbc-scope` block far
   above (which set the 28px rhythm). Same scoping rule: it
   reaches ONLY windows whose content has been converted, so
   the ~36 unconverted windows are untouched until their own
   stage. DO NOT loosen the selector.

   ⚠⚠ THIS LANDS ON ALL 28 ALREADY-CONVERTED WINDOWS AT ONCE,
   including screens the owner has approved (the four
   Superadmin dashboard windows, the calendar's two, the
   request pop-ups). That is the POINT of deciding a house
   frame — but it is why this is its own commit and never a
   side effect of converting one screen.
   ---------------------------------------------------------- */

/* P-1 A: the title carries our heading type. Bootstrap renders
   `.modal-title` as an h5 with its own size and family. */
.modal-content.pbc-scope .modal-title{
  font-family:var(--pbc-font-heading);
  font-size:var(--pbc-text-lg);
  font-weight:var(--pbc-weight-semibold);
  color:var(--pbc-ink-heading);
  line-height:var(--pbc-leading-snug);
  margin:0;
}

/* P-2 A: the footer is a tinted strip so the buttons read as a
   zone of their own, and both sit at the END.
   ⚠ `justify-content` is stated because Bootstrap's own
   `.modal-footer` is `justify-content:flex-end` only by
   default — a utility class on any one window could have
   changed it, and the house rule should not depend on that. */
.modal-content.pbc-scope .modal-footer{
  justify-content:flex-end;
  background:var(--pbc-surface-soft);
}

/* ⚠⚠ THE DARK OUT-SPECIFICATION IS LOAD-BEARING — DO NOT DROP IT.
   `dark-mode.css:124` sets `body.dark-mode .modal-content` to a
   hardcoded #1e2640 at specificity (0,2,1). A plain
   `.modal-content.pbc-scope` is only (0,2,0) and LOSES, so in
   dark a converted window would sit on a legacy colour while
   its new footer strip used a token — the two are unrelated
   values and the strip reads as a mistake. Repeating the
   `body.dark-mode` prefix takes it to (0,3,1) and wins.
   This is the same over-qualification K-4.5 needed for
   `#header .dropdown-menu`; it looks redundant and is not. */
.modal-content.pbc-scope{background:var(--pbc-surface)}
body.dark-mode .modal-content.pbc-scope{
  background:var(--pbc-surface);
  border-color:var(--pbc-border);
}
body.dark-mode .modal-content.pbc-scope .modal-header,
body.dark-mode .modal-content.pbc-scope .modal-footer{border-color:var(--pbc-border)}
body.dark-mode .modal-content.pbc-scope .modal-footer{background:var(--pbc-surface-soft)}

/* ----------------------------------------------------------
   P-3 A — THE HOUSE "ARE YOU SURE?" DIALOG.
   ----------------------------------------------------------
   Driven entirely by public/assets/js/pbc-dialog.js. It is
   deliberately NOT a Bootstrap modal: its whole job is to be
   answerable while a Bootstrap window is already open behind
   it (the "Not approve" case), and stacking two Bootstrap
   modals is the thing K-4.21 forbade.

   ⚠ Its scrim carries its own z-index rather than reusing
   `.pbc-scrim` (which sits at --pbc-z-overlay, 1040, BELOW
   Bootstrap's modal at 1055). See --pbc-z-dialog.
   ---------------------------------------------------------- */
.pbc-dlg{
  position:fixed;inset:0;
  z-index:var(--pbc-z-dialog);
  display:flex;align-items:center;justify-content:center;
  padding:var(--pbc-space-4);
  background:var(--pbc-overlay);
}
.pbc-dlg[hidden]{display:none}
.pbc-dlg__card{
  width:100%;max-width:var(--pbc-modal-w-sm);
  background:var(--pbc-surface);
  border-radius:var(--pbc-radius-modal);
  box-shadow:var(--pbc-shadow-lg);
  overflow:hidden;
  /* the card never grows past the viewport; only its body scrolls */
  display:flex;flex-direction:column;max-height:calc(100vh - var(--pbc-space-8));
}
.pbc-dlg__card--md{max-width:var(--pbc-modal-w)}
.pbc-dlg__card--lg{max-width:var(--pbc-modal-w-lg)}
.pbc-dlg__card--xl{max-width:var(--pbc-modal-w-xl)}

/* The head reuses the design system's own modal head, so the
   dialog and a converted window are visibly one family. The
   icon tile is the ONE thing P-1 A dropped from record windows
   and kept here — the owner chose the P-3 A specimen with it. */
.pbc-dlg__head{
  display:flex;align-items:flex-start;gap:var(--pbc-space-3);
  padding:var(--pbc-card-pad);
}
.pbc-dlg__icon{
  width:44px;height:44px;flex:none;border-radius:var(--pbc-radius-chip);
  background:var(--pbc-brand-100);color:var(--pbc-brand-accent);
  display:grid;place-content:center;font-size:var(--pbc-icon);
}
.pbc-dlg__icon--danger{background:var(--pbc-danger-100);color:var(--pbc-danger-600)}
.pbc-dlg__icon--warning{background:var(--pbc-warning-100);color:var(--pbc-warning-600)}
.pbc-dlg__icon--success{background:var(--pbc-success-100);color:var(--pbc-success-600)}
.pbc-dlg__titles{flex:1;min-width:0}
.pbc-dlg__title{
  display:block;
  font-size:var(--pbc-text-lg);font-weight:var(--pbc-weight-semibold);
  color:var(--pbc-ink-heading);line-height:var(--pbc-leading-snug);
}
/* display:block on the next two for the reason recorded at
   `.pbc-row__sub` — these are <span>s built by JS. */
.pbc-dlg__sub{
  display:block;
  font-size:var(--pbc-text-sm);color:var(--pbc-ink-muted);
  margin-top:var(--pbc-space-1);
}
.pbc-dlg__body{
  display:block;
  padding-inline:var(--pbc-card-pad);padding-bottom:var(--pbc-space-5);
  font-size:var(--pbc-text-base);color:var(--pbc-ink-body);
  line-height:var(--pbc-leading-normal);
  overflow-y:auto;
  /* ⚠ min-height:0 — a flex ITEM refuses to shrink below its content
     without it, so a long message would push the buttons off the card
     instead of scrolling. Same trap as .pbc-chat-list (§14.271 add. 1). */
  min-height:0;
}
.pbc-dlg__body:empty{display:none}
.pbc-dlg__foot{
  display:flex;align-items:center;justify-content:flex-end;
  gap:var(--pbc-space-3);flex-wrap:wrap;
  padding:var(--pbc-space-4) var(--pbc-card-pad);
  border-top:var(--pbc-border-width) solid var(--pbc-border-subtle);
  background:var(--pbc-surface-soft);
}

/* ----------------------------------------------------------
   P-4 A — THE CORNER MESSAGE.
   ----------------------------------------------------------
   Same corner as today (SweetAlert's `top-end`), so nothing
   about WHEN or WHERE a message appears changes — only its
   look, and it gains dark mode. `inset-inline-end` rather than
   `right`, so it moves to the left corner in Arabic on its own.
   ---------------------------------------------------------- */
.pbc-toasts{
  position:fixed;
  top:var(--pbc-space-4);inset-inline-end:var(--pbc-space-4);
  z-index:var(--pbc-z-toast);
  display:flex;flex-direction:column;align-items:flex-end;
  gap:var(--pbc-space-2-5);
  pointer-events:none;                 /* the page stays usable behind it */
  max-width:min(420px,calc(100vw - var(--pbc-space-8)));
}
.pbc-toasts .pbc-toast{pointer-events:auto}
.pbc-toast__ico{
  width:34px;height:34px;flex:none;border-radius:var(--pbc-radius-chip);
  display:grid;place-content:center;font-size:var(--pbc-icon);
}
.pbc-toast__ico--success{background:var(--pbc-success-100);color:var(--pbc-success-600)}
.pbc-toast__ico--error  {background:var(--pbc-danger-100); color:var(--pbc-danger-600)}
.pbc-toast__ico--warning{background:var(--pbc-warning-100);color:var(--pbc-warning-600)}
.pbc-toast__ico--info   {background:var(--pbc-info-100);   color:var(--pbc-info-600)}
.pbc-toast__body{min-width:0;flex:1}
.pbc-toast__t{
  display:block;
  font-size:var(--pbc-text-base);font-weight:var(--pbc-weight-semibold);
  color:var(--pbc-ink-heading);line-height:var(--pbc-leading-snug);
}
.pbc-toast__m{
  display:block;
  font-size:var(--pbc-text-sm);color:var(--pbc-ink-muted);
  margin-top:var(--pbc-space-0-5);
}
/* the countdown, shown only on a failure — a failure needs reading
   time (6s) and the bar says how much is left. Success is a glance. */
.pbc-toast__bar{
  display:block;height:3px;border-radius:2px;
  background:var(--pbc-danger-500);
  margin-top:var(--pbc-space-2);
  transform-origin:left center;
}
[dir="rtl"] .pbc-toast__bar{transform-origin:right center}
.pbc-toast__x{
  flex:none;border:0;background:transparent;color:var(--pbc-ink-faint);
  padding:0;margin-inline-start:var(--pbc-space-2);cursor:pointer;
  font-size:var(--pbc-text-md);line-height:1;
}
.pbc-toast__x:hover{color:var(--pbc-ink-heading)}

/* ----------------------------------------------------------
   P-7 B — A PICKER'S CHOSEN THINGS, AS CHIPS ABOVE THE LIST.
   ----------------------------------------------------------
   ⚠ THE max-height IS THE WHOLE POINT AND IS NOT DECORATION.
   The owner was shown this option's trade-off and accepted it:
   the chips grow downward as you pick, so with twenty picked
   they would take over the window and push the buttons out of
   reach. Capping the strip and letting IT scroll keeps the
   list and the buttons where they were.
   ---------------------------------------------------------- */
.pbc-pickchips{
  display:flex;flex-wrap:wrap;gap:var(--pbc-space-2-5);
  max-height:104px;overflow-y:auto;
  min-height:0;               /* see the .pbc-dlg__body note above */
}
.pbc-pickchips:empty{display:none}
/* the × inside a removable pill. A real <button> so it is
   reachable by keyboard; sized to stay inside the pill's line. */
.pbc-pill__x{
  border:0;background:transparent;color:inherit;
  padding:0;margin-inline-start:var(--pbc-space-1);
  font-size:var(--pbc-text-sm);line-height:1;cursor:pointer;
  opacity:.7;
}
.pbc-pill__x:hover{opacity:1}
.pbc-pill__x:focus-visible{outline:none;box-shadow:var(--pbc-focus-ring);border-radius:var(--pbc-radius-xs)}

/* ==========================================================
   THE LONG EDIT FORM — §K K-4.33 (case edit)
   ----------------------------------------------------------
   Ported from the owner-approved gallery
   PBC Mockup/enduser-case-edit-options.html, where these were
   the gallery-local specimens .g-railsplit / .g-rail /
   .g-grid2 / .g-full / .g-sticky. Owner picks 1-A, 2-A, 3-A
   and 4-A (the last "laid out side by side as in B").

   Built for the end-user case-edit screen but deliberately
   generic — the Superadmin case-edit page is the same shape
   and can take these later without a second set of rules.
   ========================================================== */

/* --- The page split: section rail + the work column (pick 2-A) ---
   Same collapse breakpoint as .pbc-cols so the two never disagree
   about what "narrow" means. */
.pbc-editsplit{
  display:grid;
  grid-template-columns:minmax(190px,220px) minmax(0,1fr);
  gap:var(--pbc-space-6);
  align-items:start;
}

/* The rail itself. `position:sticky` needs the grid item to be able to
   exceed the viewport, which `align-items:start` above guarantees. */
/* The work column. `min-width:0` is load-bearing: a grid item defaults to
   min-width:auto and refuses to shrink below its content, so one wide table or
   a long unbroken value would push the whole column past the page. */
.pbc-editwork{min-width:0}

.pbc-secrail{
  position:sticky;
  top:var(--pbc-space-3);
  display:flex;
  flex-direction:column;
  gap:var(--pbc-space-0-5);
  max-height:calc(100vh - var(--pbc-space-8));
  overflow-y:auto;
}
.pbc-secrail__link{
  display:flex;
  align-items:baseline;
  gap:var(--pbc-space-2);
  padding:var(--pbc-space-2) var(--pbc-space-3);
  border-radius:var(--pbc-radius-sm);
  /* The marker rides the INLINE start edge so it mirrors in RTL. */
  border-inline-start:2px solid transparent;
  font-size:var(--pbc-text-sm);
  color:var(--pbc-ink-muted);
  text-decoration:none;
  line-height:var(--pbc-leading-snug);
}
.pbc-secrail__link:hover{background:var(--pbc-row-hover);color:var(--pbc-ink-heading)}
.pbc-secrail__link.is-active{
  background:var(--pbc-surface-soft);
  color:var(--pbc-ink-heading);
  font-weight:var(--pbc-weight-semibold);
  /* brand-accent, never brand-600: this is a 2px hairline and accent is the
     token that stays legible in BOTH themes (brand-600 falls away in dark). */
  border-inline-start-color:var(--pbc-brand-accent);
}
.pbc-secrail__link:focus-visible{outline:none;box-shadow:var(--pbc-focus-ring)}
.pbc-secrail__name{min-width:0;overflow-wrap:anywhere}
/* Pushed to the far end with an auto margin — nothing beside it may flex-grow
   (an auto margin does not reserve space while flex distributes free space). */
.pbc-secrail__count{
  margin-inline-start:auto;
  flex:0 0 auto;
  font-size:var(--pbc-text-xs);
  color:var(--pbc-warning-600);
  white-space:nowrap;
}

/* --- The field grid (pick 1-A) ---
   Two columns; anything long spans both. minmax(0,1fr) rather than 1fr so a
   wide control (a TomSelect box, a long option label) cannot blow the track
   out past the card. */
.pbc-fieldgrid{
  display:grid;
  grid-template-columns:repeat(2,minmax(0,1fr));
  gap:var(--pbc-space-5);
  align-items:start;
}
/* Long field types: textarea, file, multi-select, department multi-select and
   the cascading picker. Also used by the re-enter pair below. */
.pbc-fieldgrid__wide{grid-column:1 / -1}

/* --- The re-enter "confirm" pair (pick 4-A, side by side as in B) ---
   The pair is ONE full-width cell holding its own two columns, rather than two
   loose siblings in the outer grid. That is what guarantees the two boxes stay
   on the same row and, in RTL, mirror as a unit — so the original always comes
   before its confirmation instead of the grid splitting them across rows. */
.pbc-fieldpair{
  grid-column:1 / -1;
  display:grid;
  grid-template-columns:repeat(2,minmax(0,1fr));
  gap:var(--pbc-space-5);
  align-items:start;
}
/* A matching re-entry. Success ink, not a fill — this is a hint, not a state
   change, and it sits on the card surface where success-600 reads cleanly. */
.pbc-field__match{
  display:flex;
  align-items:center;
  gap:var(--pbc-space-1);
  font-size:var(--pbc-text-sm);
  color:var(--pbc-success-600);
}

/* --- Documents already attached to a file field ---
   A plain list, not rows: these are facts about the field, and the upload
   control directly beneath them is the only thing to act on. */
.pbc-filelist{
  list-style:none;
  margin:0 0 var(--pbc-space-2);
  padding:0;
  display:flex;
  flex-direction:column;
  gap:var(--pbc-space-1);
}
.pbc-filelist > li{
  display:flex;
  align-items:baseline;
  gap:var(--pbc-space-2);
  font-size:var(--pbc-text-sm);
  color:var(--pbc-ink-body);
  min-width:0;
}
.pbc-filelist > li > span:first-of-type{overflow-wrap:anywhere}
.pbc-filelist > li > i{color:var(--pbc-ink-faint);flex:none}
.pbc-filelist__when{
  margin-inline-start:auto;
  flex:none;
  font-size:var(--pbc-text-xs);
  color:var(--pbc-ink-faint);
  white-space:nowrap;
}

/* --- The section card head --- */
.pbc-sechead{
  display:flex;
  align-items:center;
  gap:var(--pbc-space-2-5);
  margin-bottom:var(--pbc-space-5);
}

/* --- The action bar (pick 3-A) ---
   Sticks to the bottom of the WINDOW, not to a card, so Save and Submit are
   reachable from anywhere in a long form.
   ⚠ Deliberately STANDALONE rather than bled to a card's edges with negative
   margins: the form ends in a variable number of section cards, so a bar that
   depended on being the last child of a particular card body would break the
   day a section is added. It carries its own surface, edge and radius. */
.pbc-actionbar{
  position:sticky;
  bottom:0;
  z-index:var(--pbc-z-sticky);
  display:flex;
  flex-wrap:wrap;
  align-items:center;
  gap:var(--pbc-space-3);
  background:var(--pbc-surface);
  /* ⚠ --pbc-border-strong, NOT --pbc-border, and the difference is measured.
     An ordinary card sits ON the canvas, so its 2.37:1 edge is separation, not
     information. This bar FLOATS OVER content that scrolls underneath it, so
     its edge is the only thing telling you where the page stops and the
     controls begin — that is 1.4.11 territory and needs 3:1. border-strong
     measures 3.40:1 light / 3.20:1 dark against the surface; --pbc-border
     measures 2.37 / 2.34 and would have failed in both themes. */
  border:1px solid var(--pbc-border-strong);
  border-radius:var(--pbc-radius-card);
  box-shadow:var(--pbc-shadow-up);
  padding:var(--pbc-space-4) var(--pbc-space-5);
  margin-block-start:var(--pbc-space-6);
}
/* The line that says WHY Submit is greyed out. Filled by the evaluator script;
   it carries no text until the first response lands, so it must not reserve a
   gap when empty. */
.pbc-actionbar__reason{
  display:flex;
  align-items:center;
  gap:var(--pbc-space-1-5);
  font-size:var(--pbc-text-sm);
  color:var(--pbc-ink-muted);
  min-width:0;
  overflow-wrap:anywhere;
}
.pbc-actionbar__reason:empty{display:none}
/* The buttons travel together to the far end and wrap AS A UNIT. */
.pbc-actionbar__acts{
  display:flex;
  flex-wrap:wrap;
  align-items:center;
  gap:var(--pbc-space-2-5);
  margin-inline-start:auto;
}

@media (max-width:991px){
  /* The rail moves above the form as a row of links, exactly as the gallery
     promised. It stops being sticky — a horizontal bar pinned to the top of a
     phone viewport eats the screen it is meant to help you read. */
  .pbc-editsplit{grid-template-columns:minmax(0,1fr)}
  .pbc-secrail{
    position:static;
    flex-direction:row;
    flex-wrap:wrap;
    max-height:none;
    gap:var(--pbc-space-1);
  }
  .pbc-secrail__link{
    border-inline-start:0;
    border-bottom:2px solid transparent;
  }
  .pbc-secrail__link.is-active{border-bottom-color:var(--pbc-brand-accent)}
  .pbc-secrail__count{margin-inline-start:var(--pbc-space-1)}
}

@media (max-width:820px){
  /* One column of fields. The pair collapses too, and because the confirm box
     is the SECOND cell it still lands directly under its original. */
  .pbc-fieldgrid,.pbc-fieldpair{grid-template-columns:minmax(0,1fr)}
}

/* ==========================================================
   PROMOTED PAGE-LOCAL BLOCKS — §K K-4.74 (§14.360, 2026-08-23)
   ----------------------------------------------------------
   These rule sets were born page-local in August 2026 because this
   file was held by a parallel session at the time (carry-overs in
   STATE since K-4.46 → K-4.64). Moved here VERBATIM — same selectors,
   same declarations — so the pages render identically; only the
   definition's home changed. Appended at the END on purpose: a
   page-local <style> used to sit after this sheet in the cascade,
   and last-in-file keeps the same tie-break order against earlier
   rules in this file.
   ========================================================== */

/* --- .pbc-permgrid + .pbc-check--* modifiers (permissions page, K-4.46/K-4.58) --- from pbc-admin/pages/organization/_permission-fields.blade.php --- */
/* Replaces Bootstrap's row/col-md-6 one-for-one: two columns on a wide screen,
   one when there is no room. col-md-12 becomes --full, which spans both. The
   wrapper divs were KEPT rather than deleted — several of them hold a whole
   sub-block, not just a label, so removing them would have restructured the page
   rather than restyled it. */
.pbc-permgrid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
  gap:var(--pbc-space-3) var(--pbc-space-6);align-items:start}
.pbc-permgrid--spaced{margin-block-start:var(--pbc-space-3)}
.pbc-permgrid__cell{min-width:0}
.pbc-permgrid__cell--full{grid-column:1 / -1}
@media (max-width:720px){.pbc-permgrid{grid-template-columns:1fr}}
/* .pbc-check itself is the shipped component — these only carry the spacing and
   emphasis the Bootstrap utility classes used to provide. */
.pbc-check--spaced{margin-block-start:var(--pbc-space-3)}
.pbc-check--indent{margin-inline-start:var(--pbc-space-6)}
.pbc-check--strong{font-weight:var(--pbc-weight-semibold);margin-block-end:var(--pbc-space-2)}
.pbc-check--danger{color:var(--pbc-danger-600)}  /* K-4.76: a check whose label is a warning ("No access to this case setup") */
.pbc-check--chip{border:var(--pbc-border-width) solid var(--pbc-border);
  border-radius:var(--pbc-radius-sm);padding:var(--pbc-space-1) var(--pbc-space-2-5);
  background:var(--pbc-surface)}

/* --- .pbc-wvalue (Reports widget headline value, K-4.52) --- from pbc-admin/pages/organization/widgets/_value.blade.php --- */
.pbc-wvalue{display:flex;flex-direction:column;gap:var(--pbc-space-1);
  margin-block-end:var(--pbc-space-5)}
.pbc-wvalue--flush{padding-inline:var(--pbc-card-pad);
  padding-block-start:var(--pbc-card-pad);margin-block-end:var(--pbc-space-4)}

/* --- .pbc-gpick member picker (group permissions page, K-4.64) --- from pbc-admin/pages/organization/groupPermissions.blade.php --- */
/* §K K-4.64 — the member picker. Page-local because pbc-components.css is
   held by a parallel session; CARRY-OVER: promote when it frees up. */
.pbc-gpick {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: var(--pbc-space-2) var(--pbc-space-5);
}
.pbc-gpick__row {
    display: flex; align-items: center; gap: var(--pbc-space-3);
    padding: var(--pbc-space-2) var(--pbc-space-3);
    border-radius: var(--pbc-radius-sm);
    cursor: pointer; margin: 0;
}
.pbc-gpick__row:hover { background: var(--pbc-row-hover); }
.pbc-gpick__row input[type="checkbox"] {
    accent-color: var(--pbc-brand-600); width: 16px; height: 16px; flex: none;
}
.pbc-gpick__who { display: flex; flex-direction: column; min-width: 0; }
.pbc-gpick__who b { color: var(--pbc-ink-heading); font-weight: var(--pbc-weight-semibold); }
.pbc-gpick__id { font-size: var(--pbc-text-sm); color: var(--pbc-ink-muted); }

/* --- .pbc-ucount / .pbc-subtabs / .pbc-ufilter / .pbc-udd / .pbc-uprog / .pbc-gmembers (the organisation users box, K-4.63) --- from pbc-admin/pages/organization/components/user.blade.php --- */
/* §K K-4.63 — the users box. Page-local because pbc-components.css is
   held by a parallel session; CARRY-OVER: promote when it frees up. */
.pbc-ucount {
    display: inline-flex; align-items: center; justify-content: center;
    min-inline-size: 20px; padding-inline: 6px; margin-inline-start: 6px;
    background: var(--pbc-surface-sunken); color: var(--pbc-ink-muted);
    border-radius: var(--pbc-radius-pill);
    font-size: var(--pbc-text-xs); font-weight: var(--pbc-weight-semibold);
}
.pbc-subtabs { border-block-end: 0; gap: var(--pbc-space-5); }
.pbc-subtabs .pbc-tab { font-size: var(--pbc-text-sm); }

.pbc-ufilter { display: flex; align-items: center; gap: var(--pbc-space-4); flex-wrap: wrap; }
.pbc-ufilter__label { font-size: var(--pbc-text-sm); font-weight: var(--pbc-weight-semibold); color: var(--pbc-ink-heading); flex: none; }
.pbc-ufilter__result { font-size: var(--pbc-text-sm); color: var(--pbc-ink-muted); font-variant-numeric: tabular-nums; flex: none; }

.pbc-udd { position: relative; flex: none; }
.pbc-udd__menu {
    position: absolute; top: calc(100% + 6px); inset-inline-start: 0; z-index: 40;
    min-inline-size: 260px; max-block-size: 320px; overflow-y: auto;
    background: var(--pbc-surface);
    border: var(--pbc-border-width) solid var(--pbc-border);
    border-radius: var(--pbc-radius-card);
    box-shadow: var(--pbc-shadow-lg, 0 10px 30px rgba(22, 41, 62, .18));
    padding: var(--pbc-space-2);
}
.pbc-udd__row {
    display: flex; align-items: center; gap: var(--pbc-space-3);
    padding: var(--pbc-space-2) var(--pbc-space-3);
    border-radius: var(--pbc-radius-sm);
    font-size: var(--pbc-text-sm); color: var(--pbc-ink-body);
    cursor: pointer; margin: 0;
}
.pbc-udd__row:hover { background: var(--pbc-row-hover); }
.pbc-udd__row > span:first-of-type { flex: 1 1 auto; }
.pbc-udd__row input[type="checkbox"] { accent-color: var(--pbc-brand-600); width: 16px; height: 16px; flex: none; }
.pbc-udd__n {
    flex: none; min-inline-size: 26px; text-align: end;
    font-variant-numeric: tabular-nums;
    font-size: var(--pbc-text-sm); font-weight: var(--pbc-weight-semibold);
    color: var(--pbc-ink-muted);
}

.pbc-uprog { display: flex; flex-direction: column; gap: 6px; }
.pbc-uprog__label { font-size: var(--pbc-text-sm); color: var(--pbc-ink-muted); font-variant-numeric: tabular-nums; }

.pbc-gmembers { display: inline-flex; align-items: center; gap: 4px; }
.pbc-gmembers__more { font-size: var(--pbc-text-sm); color: var(--pbc-ink-muted); font-variant-numeric: tabular-nums; }

/* --- .pbc-phasebar / .pbc-phasenav (the case page phase bar, K-4.54/K-4.55) --- from user/pages/case/view.blade.php --- */
/* The frame scrolls; the scrollbar is hidden because the owner
   asked never to have to drag it. Dragging still WORKS (trackpad,
   shift-wheel, keyboard) — hiding the bar removes the chore, it
   does not trap anyone who wants to look ahead.
   ⚠ Safari needs the -webkit- pseudo-element; `scrollbar-width`
   alone does nothing there, and Safari is the reference browser. */
.pbc-phasebar{overflow-x:auto;scrollbar-width:none;-ms-overflow-style:none;
  overscroll-behavior-x:contain}
.pbc-phasebar::-webkit-scrollbar{display:none}
/* §K K-4.55 — the owner asked for a button each side so a reader can walk
   back to earlier phases instead of only being shown the current one.
   The row is flex, so in Arabic it mirrors and "earlier" lands on the
   right by itself — no second rule. */
.pbc-phasenav{display:flex;align-items:flex-start;gap:var(--pbc-space-2)}
.pbc-phasenav .pbc-phasebar{flex:1 1 auto;min-width:0}
.pbc-phasenav__btn{flex:none}
/* ⚠⚠ `.pbc-btn` sets `display:inline-flex`, which OVERRIDES the `hidden`
   attribute's UA `display:none`. Without this line a short workflow would
   render two dead arrows that the script believes it has hidden. */
.pbc-phasenav__btn[hidden]{display:none}
/* The glyph has to mirror in RTL — the chevron is a picture of a
   direction, and unlike the layout it does not flip itself. */
[dir="rtl"] .pbc-phasenav__btn .bi{transform:scaleX(-1)}
/* Fixed, equal step widths are what make the strip scrollable at all
   (the shipped `flex:1 1 0` squeezes N phases into the visible width,
   which is exactly the crowding the owner rejected).
   ⚠ They must stay EQUAL: `.pbc-wizbar__step::after` draws the rail
   with calc(50% ± 20px), which only lands on the next marker when
   every step is the same width. */
/* `1 0 148px` — GROW so a short workflow still spans the card exactly
   as the wizard does, but NEVER SHRINK, so a long one overflows and
   the frame scrolls instead of crushing the labels. A plain
   `0 0 148px` was rejected: it would leave a 3-phase case as a stubby
   bar with dead space beside it. */
.pbc-phasebar .pbc-wizbar__step{flex:1 0 148px}
/* ⚠ The component hides non-current labels under 640px so five of
   them cannot stack into a mush. That rule is right for the wizard
   and WRONG here — this strip scrolls, so there is room for every
   label at any width. (0,2,0) beats the (0,1,0) inside the media
   query regardless of source order. */
.pbc-phasebar .pbc-wizbar__label{display:block}

/* ==========================================================
   DATE FIELD — §K K-4.80 (2026-08-23, §14.369)
   ==========================================================
   components/date-field.blade.php: Day / Month / Year selects side by side.
   Was a Bootstrap `row g-2` with three `col-4`s; the wrapper is the grid now.
   The hidden value input inside it is display:none, so it takes no track.
   The confirm copy (re-enter) repeats the grid under its own label. */
.pbc-date-field{
  display:grid;
  grid-template-columns:repeat(3,minmax(0,1fr));
  gap:var(--pbc-space-2);
}
.pbc-date-field__confirm{display:block;margin-block-start:var(--pbc-space-3)}
/* Three selects share one field's width (~86px each in a half-column), so the
   house select padding (12px + 32px) left 42px for "Month" and clipped it —
   measured on the Superadmin case edit. Tighter padding here only, chevron
   moved in with it; the arrow glyph itself is the shared one. */
.pbc-date-field .pbc-select{
  padding-inline:var(--pbc-space-2) var(--pbc-space-6);
  background-position:right var(--pbc-space-2-5) center,
                      right calc(var(--pbc-space-2-5) - 5px) center;
}
[dir="rtl"] .pbc-date-field .pbc-select{
  padding-inline:var(--pbc-space-6) var(--pbc-space-2);
  background-position:left calc(var(--pbc-space-2-5) - 5px) center,
                      left var(--pbc-space-2-5) center;
}

/* ==========================================================
   TOM SELECT ON THE HOUSE CONTROL — §K K-4.82 (2026-08-23, §14.374)
   ==========================================================
   Every <x-multiselect> renders `select.pbc-select.pbc-multiselect`; Tom Select
   (loaded from both masters) replaces it with `.ts-wrapper.pbc-select …` and
   keeps the classes on the wrapper. Its bootstrap5 theme then painted the box
   36.5px tall, 6px-radius, Bootstrap-grey, WHITE in dark — the last un-house
   control on every converted window (the §14.357 carry-over), and in a filter
   tray it sat visibly shorter than the selects beside it. The wrapper is made
   transparent (it carried .pbc-select's border + height + caret) and the real
   box, `.ts-control`, gets the house control geometry and tokens. Pills and the
   dropdown follow the pill / menu tokens. Specificity (0,3,0)+ beats the theme. */
.ts-wrapper.pbc-select{
  height:auto;min-height:0;padding:0;border:0;background:transparent;background-image:none;box-shadow:none;
}
.ts-wrapper.pbc-select .ts-control{
  min-height:var(--pbc-control-h);
  padding-block:var(--pbc-space-1-5);
  padding-inline:var(--pbc-space-3) var(--pbc-space-8);
  border:var(--pbc-border-width) solid var(--pbc-border);
  border-radius:var(--pbc-radius-btn);
  background:var(--pbc-surface);
  color:var(--pbc-ink-body);
  font-size:var(--pbc-text-base);
  box-shadow:none;
  transition:border-color var(--pbc-transition),box-shadow var(--pbc-transition);
}
.ts-wrapper.pbc-select:hover .ts-control{border-color:var(--pbc-border-strong)}
.ts-wrapper.pbc-select.focus .ts-control,
.ts-wrapper.pbc-select.dropdown-active .ts-control{border-color:var(--pbc-brand-accent);box-shadow:var(--pbc-focus-ring)}
.ts-wrapper.pbc-select .ts-control>input{color:var(--pbc-ink-body);font-size:var(--pbc-text-base)}
.ts-wrapper.pbc-select .ts-control>input::placeholder{color:var(--pbc-ink-faint)}
/* the chosen items — the neutral pill */
.ts-wrapper.pbc-select.multi .ts-control>div{
  background:var(--pbc-neutral-100);color:var(--pbc-neutral-600);
  border:var(--pbc-border-width) solid var(--pbc-neutral-border);
  border-radius:var(--pbc-radius-pill);
  padding-block:0;padding-inline:var(--pbc-space-2-5);
  margin:2px var(--pbc-space-1-5) 2px 0;
  font-size:var(--pbc-text-sm);line-height:1.7;
  /* one line per pill: a long label is cut with an ellipsis rather than
     wrapping and growing the box (the remove "×" stays visible) */
  max-width:calc(100% - 3em);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  /* ⚠ the vendor's remove_button rule sets display:inline-flex and
     padding-right:0 !important on .item — both beaten here on purpose: a flex
     item cannot carry an ellipsis, and the × needs its room. */
  display:block;position:relative;padding-inline-end:1.8em !important;
}
/* the remove_button plugin's × — pinned to the pill's end so the ellipsis
   can never swallow it; the vendor border-left divider is dropped */
.ts-wrapper.pbc-select.multi .ts-control>div .remove{
  position:absolute;inset-inline-end:.35em;top:0;bottom:0;
  display:inline-flex;align-items:center;
  border:0;padding:0;margin:0;
  color:inherit;opacity:.7;
}
.ts-wrapper.pbc-select.multi .ts-control>div .remove:hover{opacity:1;background:transparent}
/* once something is chosen the typing slot shrinks beside the pills instead of
   dropping to its own line under them (which made a one-item box two lines
   tall); the placeholder text is hidden visually, not removed — the masters'
   init keeps hidePlaceholder:false on purpose */
.ts-wrapper.pbc-select.multi.has-items .ts-control>input{flex:1 1 2em;min-width:2em;width:2em !important}
.ts-wrapper.pbc-select.multi.has-items .ts-control>input::placeholder{color:transparent}
.ts-wrapper.pbc-select.multi .ts-control>div.active{background:var(--pbc-brand-accent);color:var(--pbc-ink-on-brand);border-color:transparent}
/* the options panel — the house menu */
.ts-wrapper.pbc-select .ts-dropdown{
  margin-top:var(--pbc-space-1);
  /* wider than a narrow tray field so option labels read on one line */
  width:max-content;min-width:100%;max-width:min(360px,80vw);
  background:var(--pbc-surface);color:var(--pbc-ink-body);
  border:var(--pbc-border-width) solid var(--pbc-border);
  border-radius:var(--pbc-radius-btn);
  box-shadow:var(--pbc-shadow-md);
}
.ts-wrapper.pbc-select .ts-dropdown .option{padding-block:var(--pbc-space-2);padding-inline:var(--pbc-space-3)}
.ts-wrapper.pbc-select .ts-dropdown .active{background:var(--pbc-surface-hover);color:var(--pbc-ink-heading)}
.ts-wrapper.pbc-select .ts-dropdown .option.selected{color:var(--pbc-brand-accent)}
