/* ============================================================================
   BioProfile - the layout shell's own stylesheet, and the back office's
   form kit. Architecture 33: the chrome lives in ONE place per access layer,
   so its styles live here rather than in any page.

   Everything below is either the shell (badge, footer, account menu) or the
   controls a back-office screen needs and the design system does not carry yet
   (fields, dialogs, drag rows, empty states). Nothing here is page-specific:
   a rule that only one screen needs belongs on that screen.
   ========================================================================== */

/* ---- the shell ------------------------------------------------------------ */
/* The back-office badge and organisation name, the same drawing the approved
   admin proposal pages carry (.rc-badge in app/admin/admin.css began as the
   admin console's own; the shell owns the topbar now, so the shell carries
   them, and a member page needs no admin stylesheet to draw its chrome). */
.rc-badge {
  display: inline-flex; align-items: center; gap: 6px; padding: 4px 11px;
  border-radius: var(--r-pill); background: var(--ink-dark); color: #fff;
  font-size: var(--t-eyebrow); font-weight: var(--w-med); text-transform: uppercase;
  letter-spacing: .09em; white-space: nowrap;
}
.rc-org { font-size: var(--t-sm); color: var(--ink-2); white-space: nowrap; }
/* The language slot the app's i18n fills. Every page that carries its own
   topbar gives this span the inline-flex row as an inline style; the shell drew
   it as a bare inline span, so on a phone the two language buttons stacked EN
   over NL inside a 64px bar. The shell's slot is the same row those pages get.
   (Operator's mobile sweep, 2026-09-02.) */
[data-lang-switch] { display: inline-flex; gap: 2px; flex: none; align-items: center; }

/* The account chip's chevron moved to the design system (components.css,
   beside .user-chip) with T261: the one profile control is drawn on the older
   member pages as well, and they do not load this sheet. */

/* The back-office nav rows. The consumer app paints its four pillars in their
   own colours; a back office has no pillars, so its rows are slate and the
   current one is teal. These rules were in the result console's own stylesheet
   and belong here now: the shell draws the nav, so the shell carries its look,
   and a page that imports the shell needs no second stylesheet to see it. */
.nav__item--adm .nav__link { background: var(--bp-slate); }
.nav__item--adm.is-active .nav__link { background: var(--bp-teal); }
/* An office row while it waits or while its page does not exist keeps the slate
   ground; the not-clickable look itself is the design system's (components.css,
   under the navigation), because the member pages that are not on this shell
   draw the same nav and must draw those states the same way. */
.nav__item--adm.is-soon .nav__link, .nav__item--adm.is-wait .nav__link { background: var(--bp-slate); }
/* Real words instead of the app's short pillar names: on a phone the labels
   have to shrink to the short form or the nav pushes the page sideways.
   A strip that still does not fit SCROLLS, never wraps: wrapping the items
   into a tile grid is what the 2 September review rejected, and the house
   already answers a tight row by scrolling it (.tabs, .bp-w-jump__row). */
@media (max-width: 899px) {
  .nav__list { overflow-x: auto; scrollbar-width: none; }
  .nav__list::-webkit-scrollbar { display: none; }
  .nav__item--adm { flex: 1 0 auto; }
  .nav__item--adm .nav__link { padding-inline: 14px; }
  .nav__item--adm .nav__ico-label { min-width: 0; max-width: 100%; }
  .nav__item--adm .nav__lbl-f { display: none; }
  .nav__item--adm .nav__lbl-s { display: inline; }
  .nav__item--adm .nav__ico-label > span:last-child {
    font-size: var(--t-xs); letter-spacing: 0; line-height: 1; text-align: center;
    white-space: nowrap;
  }
}
@media (max-width: 679px) { .rc-org { display: none; } }

.user-menu__out {
  font-size: var(--t-sm); color: var(--bp-teal); font-weight: var(--w-med);
}
.user-menu__out:hover { text-decoration: underline; }

/* The footer: the product's own close, not a status line. The brand mark and
   the platform line on the left, the environment on the right, on the same
   paper the topbar sits on. */
.shell-foot {
  display: flex; flex-wrap: wrap; gap: var(--s-3) var(--s-5); align-items: center;
  justify-content: space-between;
  margin-top: var(--s-10); padding: var(--s-6) var(--s-5);
  border-top: 1px solid var(--line);
  background: var(--paper); color: var(--ink-3); font-size: var(--t-xs);
}
.shell-foot__brand { display: inline-flex; align-items: center; gap: 10px; min-width: 0; }
.shell-foot__brand img { height: 20px; width: auto; opacity: .75; }
.shell-foot__l { letter-spacing: .02em; }
.shell-foot__r { font-variant-numeric: tabular-nums; text-transform: uppercase;
  letter-spacing: var(--ls-caps); font-size: var(--t-eyebrow); }
@media (min-width: 900px) { .shell-foot { padding-inline: var(--s-10); } }

/* ---- the loading skeleton -------------------------------------------------
   What a screen shows while its data is on the wire: the page's own shapes,
   quietly shimmering, never a sentence pretending to be progress. Pages carry
   this markup inside [data-bp-content] with aria-hidden and aria-busy on the
   screen, and the first real paint replaces it. */
.bp-skel { display: grid; gap: var(--s-4); margin-top: var(--s-6); }
.bp-skel__bar, .bp-skel__card {
  display: block; border-radius: var(--r-md);
  background: linear-gradient(90deg, var(--paper-3) 25%, var(--paper-2) 50%, var(--paper-3) 75%);
  background-size: 200% 100%; animation: bp-skel 1.2s linear infinite;
}
.bp-skel__bar { height: 16px; }
.bp-skel__bar--h { height: 34px; width: min(360px, 70%); margin-bottom: var(--s-2); }
.bp-skel__card { height: 108px; border-radius: var(--r-lg); }
@keyframes bp-skel { to { background-position: -200% 0; } }
@media (prefers-reduced-motion: reduce) {
  .bp-skel__bar, .bp-skel__card { animation: none; }
}

/* ---- page furniture ------------------------------------------------------- */
.bp-head { display: flex; flex-wrap: wrap; gap: var(--s-4); align-items: flex-end;
  justify-content: space-between; margin: var(--s-6) 0 var(--s-5); }
.bp-head h1 { font-size: var(--t-h1); font-weight: var(--w-med); }
.bp-head p { color: var(--ink-2); font-size: var(--t-sm); line-height: var(--lh-body); max-width: 74ch; margin-top: 6px; }
.bp-head__act { display: flex; gap: 8px; flex-wrap: wrap; }

.bp-sec { margin-top: var(--s-8); }
.bp-sec__head { display: flex; flex-wrap: wrap; gap: var(--s-3); align-items: baseline;
  justify-content: space-between; margin-bottom: var(--s-4); }
.bp-sec__head h2 { font-size: var(--t-h2); font-weight: var(--w-med); }
.bp-sec__head p { color: var(--ink-2); font-size: var(--t-sm); margin-top: 4px; max-width: 74ch; }

.bp-stats { display: flex; flex-wrap: wrap; gap: var(--s-4); margin-top: var(--s-4); }
.bp-stat { background: var(--paper); border: 1px solid var(--line); border-radius: var(--r-lg);
  padding: 12px 18px; min-width: 120px; }
.bp-stat b { display: block; font-size: 1.4rem; font-weight: var(--w-semi); font-variant-numeric: tabular-nums; }
.bp-stat span { font-size: var(--t-xs); color: var(--ink-3); }
/* The tiles size to their own words on a wide screen, which is right there and
   ragged on a phone: four tiles wrapped two and two at four different widths,
   none of the edges lining up. Below 560 they are a grid, so the second row
   sits under the first. */
@media (max-width: 560px) {
  .bp-stats { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
  .bp-stat { min-width: 0; padding: 12px 14px; }
}

.bp-note { font-size: var(--t-sm); color: var(--ink-2); line-height: var(--lh-body); max-width: 80ch; }
.bp-note b { color: var(--ink); font-weight: var(--w-med); }
.bp-mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .8rem; letter-spacing: .02em; }
.bp-num { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
.bp-empty { padding: var(--s-6) var(--s-5); text-align: center; border: 1px dashed var(--line-2);
  border-radius: var(--r-lg); background: var(--paper-2); }
.bp-empty b { display: block; font-size: var(--t-body); font-weight: var(--w-med); color: var(--ink); }
.bp-empty p { margin-top: 6px; font-size: var(--t-sm); color: var(--ink-2); }
.bp-rowbtns { display: flex; gap: 6px; flex-wrap: wrap; }

/* Three state words the house pill does not carry yet. The proposals parked
   the same three in their own stylesheet because that batch was not allowed to
   touch a sheet the live app loads; the back office needs them for real, so
   they live here beside the rest of its kit. */
.pill-tag--mute { background: var(--paper-3); color: var(--ink-2); }
.pill-tag--core { background: var(--bp-teal-08); color: var(--bp-teal); }
.pill-tag--draft { background: var(--warn-08); color: var(--ink-2); }

/* A demo row says so on its face. Seeded example data must never be mistaken
   for an onboarded partner. */
.bp-demo { display: inline-flex; align-items: center; gap: 5px; white-space: nowrap; font-size: var(--t-xs);
  font-weight: var(--w-semi); text-transform: uppercase; letter-spacing: var(--ls-caps);
  color: #8a5a12; background: var(--warn-08); padding: 3px 8px; border-radius: var(--r-pill); }

/* ---- the quiet row action --------------------------------------------------
   The 2026-09-02 review's rule: content reads first, buttons second, and every
   row's actions sit at the SAME x in ONE column, uniform size, uniform order.
   Card-level actions stay the ghost pill (.btn--ghost .btn--sm), visually
   heavier by design; a row inside a card or a table gets this quiet text
   button instead. The one special action a row can carry (send sales here)
   takes the accent colour, same shape, same column. */
.bp-qbtn {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 36px; padding: 6px 10px; border: 0; border-radius: var(--r-md);
  background: none; color: var(--ink-3); cursor: pointer;
  font-family: var(--font); font-size: var(--t-eyebrow); font-weight: var(--w-semi);
  text-transform: uppercase; letter-spacing: var(--ls-caps); white-space: nowrap;
}
.bp-qbtn:hover { background: var(--bp-teal-08); color: var(--bp-teal); }
.bp-qbtn--del:hover { background: var(--alert-08); color: var(--alert); }
.bp-qbtn--accent { color: var(--bp-teal); }
.bp-act { display: inline-flex; gap: 2px; justify-content: flex-end; align-items: center; }

/* ---- the admin card --------------------------------------------------------
   One hierarchy, from the same review: a header row (grip, name, ONE chip row,
   card-level actions in ONE right-aligned group), a labelled facts row instead
   of stacked grey prose, and the detail layer (contacts) on its own indented
   surface so card and contents never blur. */
.bp-card { background: var(--paper); border: 1px solid var(--line); border-radius: var(--r-lg);
  padding: var(--s-5); box-shadow: var(--sh-1); }
.bp-card + .bp-card { margin-top: 10px; }
.bp-card.is-first { border-color: var(--bp-teal-40); }
.bp-card.is-dragging { opacity: .5; }
.bp-card__head { display: flex; flex-wrap: wrap; gap: 8px 10px; align-items: center; }
.bp-card__head > b { font-size: var(--t-body); font-weight: var(--w-med); color: var(--ink); }
.bp-card__act { margin-left: auto; display: flex; gap: 8px; flex-wrap: wrap; }
@media (max-width: 679px) { .bp-card__act { margin-left: 0; width: 100%; } }
.bp-card__facts { display: flex; flex-wrap: wrap; gap: 10px 28px; margin-top: 12px; }
/* ONE vertical rhythm for every admin card at phone width (operator's mobile
   review, 2026-09-02). The facts row is a wrapping flex line from 561px up,
   which reads fine while there is room to place a pair per line; below that the
   wrap was ragged - two facts, then one, then two - and a long value dragged
   its neighbour with it. On a phone the facts are a two-column grid on a fixed
   rhythm, and a fact that carries an address or a note takes the whole width
   instead of wrapping four lines deep in half of one. */
@media (max-width: 560px) {
  .bp-card { padding: var(--s-4); }
  .bp-card + .bp-card { margin-top: 8px; }
  .bp-card__head { gap: 8px; }
  .bp-card__head > b { flex: 1 1 100%; }
  .bp-card__act { gap: 6px; margin-top: 2px; }
  .bp-card__act .btn { flex: 1 1 auto; }
  .bp-card__facts { display: grid; grid-template-columns: 1fr 1fr; gap: 12px 16px; margin-top: 14px; }
  .bp-fact--wide { grid-column: 1 / -1; }
  .bp-card__sub { padding: 2px 8px; }
}
.bp-fact span { display: block; font-size: var(--t-eyebrow); text-transform: uppercase;
  letter-spacing: var(--ls-caps); color: var(--ink-3); font-weight: var(--w-med); margin-bottom: 2px; }
.bp-fact b { font-size: var(--t-sm); font-weight: var(--w-med); color: var(--ink-2); }
.bp-fact.is-bad b { color: var(--alert); }
.bp-fact.is-empty b { color: var(--ink-3); font-weight: var(--w-reg); }
.bp-fact__note { display: block; margin-top: 2px; font-size: var(--t-xs); color: var(--ink-3);
  max-width: 52ch; line-height: var(--lh-snug); font-weight: var(--w-reg); }
.bp-nowrap { white-space: nowrap; }

/* the contact list: one grid for ALL rows, so the three action slots are three
   real columns and every row's buttons land at the same x by construction */
.bp-card__sub { margin-top: var(--s-4); border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--paper-2); padding: 2px 10px; }
.bp-card__sub-grid { display: grid; grid-template-columns: minmax(0, 1fr) max-content max-content max-content;
  align-items: center; }
.bp-contact { display: contents; }
.bp-contact > * { padding: 6px 4px; border-top: 1px dashed var(--line); min-height: 44px;
  display: flex; align-items: center; }
.bp-contact:first-child > * { border-top: 0; }
.bp-contact__who { min-width: 0; font-size: var(--t-sm); color: var(--ink-2);
  gap: 8px; flex-wrap: wrap; }
.bp-contact__who .bp-contact__v { color: var(--ink); font-weight: var(--w-med); overflow-wrap: anywhere; }
.bp-contact__who svg { width: 15px; height: 15px; flex: none; color: var(--ink-4); }
@media (max-width: 679px) {
  .bp-card__sub-grid { display: block; }
  .bp-contact { display: flex; flex-wrap: wrap; align-items: center; gap: 0 2px;
    padding: 6px 0; border-top: 1px dashed var(--line); }
  .bp-contact:first-child { border-top: 0; }
  .bp-contact > * { border-top: 0; padding: 2px 4px; min-height: 0; }
  .bp-contact__who { flex: 1 1 100%; min-height: 34px; }
}

/* ---- the card list a lab or a field is drawn as --------------------------- */
.bp-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--s-4);
  align-items: center; padding: 14px var(--s-5); border: 1px solid var(--line);
  border-radius: var(--r-lg); background: var(--paper); box-shadow: var(--sh-1); }
.bp-row + .bp-row { margin-top: 8px; }
.bp-row b { font-size: var(--t-body); font-weight: var(--w-med); color: var(--ink); }
.bp-row.is-first { border-color: var(--bp-teal-40); }
.bp-row.is-dragging { opacity: .5; }
.bp-row__meta { display: flex; flex-wrap: wrap; gap: 4px 10px; align-items: center;
  margin-top: 5px; font-size: var(--t-xs); color: var(--ink-3); }
.bp-row__meta span + span::before { content: "\00b7"; margin-right: 10px; color: var(--line-2); }
.bp-grip { cursor: grab; color: var(--ink-4); padding: 0 6px; }
.bp-grip:active { cursor: grabbing; }
@media (max-width: 679px) {
  .bp-row { grid-template-columns: minmax(0, 1fr); }
}

/* ---- fields --------------------------------------------------------------- */
.bp-form { display: grid; gap: var(--s-4); }
.bp-form--2 { grid-template-columns: 1fr 1fr; }
@media (max-width: 679px) { .bp-form--2 { grid-template-columns: 1fr; } }
.bp-field { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.bp-field > label { font-size: var(--t-eyebrow); text-transform: uppercase;
  letter-spacing: var(--ls-caps); font-weight: var(--w-semi); color: var(--ink-3); }
.bp-field input[type=text], .bp-field input[type=email], .bp-field input[type=number],
.bp-field input[type=date], .bp-field select, .bp-field textarea {
  width: 100%; padding: 10px 12px; border-radius: var(--r-md);
  border: 1px solid var(--line-2); background: var(--paper); color: var(--ink);
  font-size: var(--t-sm);
}
.bp-field textarea { min-height: 84px; resize: vertical; }
.bp-field input:focus, .bp-field select:focus, .bp-field textarea:focus {
  outline: 2px solid var(--bp-teal); outline-offset: 1px; border-color: transparent;
}
.bp-field small { font-size: var(--t-xs); color: var(--ink-3); }
.bp-check { display: flex; gap: 8px; align-items: flex-start; font-size: var(--t-sm); color: var(--ink-2); }
.bp-check input { margin-top: 3px; }

/* ---- the house checkbox ----------------------------------------------------
   ONE control, ONE size, everywhere a row is ticked (operator's mobile review,
   2026-09-02). The native control it replaces had no size of its own, so in a
   stacked table cell it became a grid item and stretched to the whole value
   column: a 40px blue slab in one row beside a 13px one in the next, on the
   same card. This one is 20px by construction, drawn in the brand's ink, and
   flex:none keeps it that size in every container the back office has. */
.bp-box {
  appearance: none; -webkit-appearance: none;
  width: 20px; height: 20px; flex: none; margin: 0; padding: 0;
  border: 1.5px solid var(--line-2); border-radius: 6px; background: var(--paper);
  cursor: pointer; position: relative; display: inline-block; vertical-align: middle;
  transition: background var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease);
}
.bp-box:hover { border-color: var(--bp-teal); }
.bp-box:checked { background: var(--bp-teal); border-color: var(--bp-teal); }
.bp-box:checked::after {
  content: ""; position: absolute; left: 6px; top: 2px; width: 4px; height: 9px;
  border: solid #fff; border-width: 0 2px 2px 0; transform: rotate(45deg);
}
.bp-box:focus-visible { outline: 2px solid var(--bp-teal); outline-offset: 2px; }
.bp-box:disabled { opacity: .45; cursor: default; }
.bp-err { color: var(--alert); font-size: var(--t-xs); }

/* ---- the dialog every create and edit opens ------------------------------- */
.bp-scrim { position: fixed; inset: 0; z-index: 80; background: rgba(17, 24, 24, .45);
  display: grid; place-items: center; padding: var(--s-4); overflow: auto; }
.bp-dialog { background: var(--paper); border-radius: var(--r-lg); box-shadow: var(--sh-3);
  width: min(560px, 100%); max-height: 92dvh; overflow: auto; padding: var(--s-6); }
.bp-dialog h2 { font-size: var(--t-h3); font-weight: var(--w-med); }
.bp-dialog > p { margin-top: 6px; color: var(--ink-2); font-size: var(--t-sm); line-height: var(--lh-body); }
.bp-dialog__body { margin-top: var(--s-5); }
.bp-dialog__act { display: flex; gap: 8px; justify-content: flex-end; flex-wrap: wrap; margin-top: var(--s-6); }

/* ---- toast + gate --------------------------------------------------------- */
.bp-toast { position: fixed; left: 50%; bottom: 26px; transform: translateX(-50%);
  z-index: 90; background: var(--ink); color: #fff; font-size: var(--t-sm);
  padding: 11px 18px; border-radius: var(--r-pill); box-shadow: var(--sh-3);
  opacity: 0; pointer-events: none; transition: opacity var(--dur-2) var(--ease); max-width: 92vw; }
.bp-toast.is-on { opacity: 1; }
.bp-toast.is-bad { background: var(--alert); }

.bp-gate { max-width: 520px; margin: var(--s-10) auto; background: var(--paper);
  border: 1px solid var(--line); border-radius: var(--r-lg); padding: var(--s-6); }
.bp-gate h1 { font-size: var(--t-h2); font-weight: var(--w-med); }
.bp-gate p { margin-top: 8px; color: var(--ink-2); font-size: var(--t-sm); line-height: var(--lh-body); }
.bp-gate__row { display: flex; gap: 8px; margin-top: var(--s-5); flex-wrap: wrap; }
.bp-gate__row input { flex: 1 1 220px; padding: 10px 12px; border: 1px solid var(--line-2);
  border-radius: var(--r-md); font-size: var(--t-sm); }
.bp-gate__msg { min-height: 1.4em; font-size: var(--t-xs); color: var(--ink-3); }
.bp-gate__msg.is-bad { color: var(--alert); }

/* ---- three additions the T216 back-office screens needed ------------------- */
/* Additive only: no existing rule changes, and every screen already on this
   sheet renders identically. */
.bp-muted { color: var(--ink-3); }
.pill-tag--live { background: var(--ok-08); color: var(--ok); }
/* A standing fact an editor has to see before they read the rows under it (the
   areas with no product rule, the rate that is still zero). Not an error state:
   it is the screen telling the truth about what it cannot do yet. */
.bp-note--warn { max-width: none; background: var(--warn-08); color: var(--ink);
  border-left: 3px solid var(--warn); border-radius: var(--r-md);
  padding: 11px 14px; }

/* ---- the closed door -------------------------------------------------------
   A back office paints no chrome until an admin is confirmed (Jesse's ruling of
   2026-09-04), so until then the page is this: the brand mark on the app's own
   ground, and one card centred under it. The card is the same .bp-gate the
   console already draws, or the .rc-gate the result-delivery screens draw; here
   it fills the door instead of a content slot, which is the whole of the move.
   No new colour and no new type size: the ground, the paper and the shadow are
   the app's own. */
.bp-door { display: grid; place-items: center; padding: var(--s-6) var(--s-4); }
.bp-door__in { width: min(520px, 100%); }
.bp-door__mark { display: block; height: 34px; width: auto; margin: 0 auto var(--s-6); }
.bp-door .bp-gate, .bp-door .rc-gate {
  margin: 0; max-width: none; width: 100%; box-shadow: var(--sh-1);
}

/* ---- the member layer's bell (T219 phase A) ---- */
.bp-bell-wrap { position: relative; display: inline-flex; margin-right: 6px; }
.bp-bell { appearance: none; border: 0; background: none; width: 40px; height: 40px; border-radius: 50%; display: grid; place-items: center;
  color: var(--ink-2); cursor: pointer; position: relative; }
.bp-bell:hover { background: var(--bp-teal-08); color: var(--bp-teal); }
.bp-bell:focus-visible { outline: 2px solid var(--bp-teal); outline-offset: 2px; }
.bp-bell svg { width: 20px; height: 20px; }
.bp-bell__n { position: absolute; top: 4px; right: 4px; min-width: 18px; height: 18px; padding: 0 5px; border-radius: 9px; background: var(--bp-teal); color: #fff;
  font-size: 11px; font-weight: var(--w-semi); display: grid; place-items: center; line-height: 1; }
.bp-bell__panel { position: absolute; right: 0; top: 46px; width: min(360px, calc(100vw - 24px)); max-height: 70vh; overflow: auto; background: var(--paper);
  border: 1px solid var(--line); border-radius: var(--r-lg); box-shadow: var(--sh-3); z-index: 60; padding: 6px; }
.bp-bell__head { display: flex; justify-content: space-between; align-items: center; padding: 8px 10px; border-bottom: 1px solid var(--line); }
.bp-bell__head b { font-size: var(--t-sm); font-weight: var(--w-med); }
.bp-bell__all { appearance: none; border: 0; background: none; color: var(--bp-teal); font: inherit; font-size: var(--t-xs); font-weight: var(--w-med); cursor: pointer; }
.bp-bell__item { display: block; padding: 10px; border-radius: var(--r-md); text-decoration: none; color: inherit; }
.bp-bell__item:hover { background: var(--bp-teal-08); }
.bp-bell__item.is-unread { background: var(--bp-sand-soft); }
.bp-bell__item b { display: block; font-size: var(--t-sm); font-weight: var(--w-med); }
.bp-bell__item span { display: block; font-size: var(--t-xs); color: var(--ink-2); line-height: var(--lh-snug); margin-top: 2px; }
.bp-bell__item small { display: block; font-size: var(--t-xs); color: var(--ink-3); margin-top: 2px; }
.bp-bell__empty { padding: 14px 10px; font-size: var(--t-sm); color: var(--ink-2); line-height: var(--lh-body); }

/* ---- the phone strip with more items than fit (T219 phase A) ----
   The expert dashboard carries six items and the back office eleven; below the
   sidebar breakpoint the strip shared the width equally and cut the last ones
   off. Such an item keeps a readable minimum and the strip scrolls sideways
   instead.

   T233 (2026-09-07): this override was written for EVERY item and so it also
   sized the member's four pillars to their own words - ANALYSE 110.7px next to
   NU 75.2px on a 390 phone, measured on app.bioprofile.com. The four pillars
   are a fixed set that always fits, so they keep the design system's equal
   quarters (.nav__item { flex:1 1 0 }) and only a nav with more items than a
   phone can hold scrolls. A pillar is any item the layer gives a colour to;
   an office row carries --adm and is the one that scrolls. */
@media (max-width: 899px) {
  .nav__list { overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch; }
  .nav__list::-webkit-scrollbar { display: none; }
  .nav__item--adm { flex: 1 0 auto; min-width: 74px; }
}
/* Under the narrowest phones the pillar label tightens rather than the tab
   growing: letter-spacing first, then the type size, and the label's own
   ellipsis (components.css) is the guard that it can never overflow. */
@media (max-width: 359px) {
  .nav__item:not(.nav__item--adm) .nav__link { letter-spacing: .01em; padding-inline: 3px; }
}
@media (max-width: 329px) {
  .nav__item:not(.nav__item--adm) .nav__link { font-size: .66rem; }
}

/* ---- the module switch (T219 phase B) ----
   Expert / Company, in the topbar, for a person who holds both. The same
   segmented shape the console's filter strip uses (.sc-seg), so it reads as
   one control and never as two loose links. */
.bp-modules { display: inline-flex; border: 1px solid var(--line-2); border-radius: var(--r-md); overflow: hidden; margin-right: 6px; }
.bp-modules[hidden] { display: none; }
.bp-modules__m { display: inline-flex; align-items: center; height: 34px; padding: 0 12px; text-decoration: none;
  font-size: var(--t-eyebrow); font-weight: var(--w-semi); text-transform: uppercase; letter-spacing: var(--ls-caps);
  color: var(--ink-2); background: var(--paper); white-space: nowrap; }
.bp-modules__m + .bp-modules__m { border-left: 1px solid var(--line-2); }
.bp-modules__m:hover { background: var(--bp-teal-08); color: var(--bp-teal); }
.bp-modules__m.is-on { background: var(--bp-teal); color: #fff; }
.bp-modules__m:focus-visible { outline: 2px solid var(--bp-teal); outline-offset: -2px; }
/* T219 UX pass: the phone keeps the tighter padding, but never the 32 px height
   a thumb misses; the 44 px floor is components.css's touch rule. */
@media (max-width: 679px) { .bp-modules__m { padding: 0 9px; height: 40px; } }
/* On a phone the switch says which module the person is in, so the layer's
   badge would only repeat it in the space it needs (the operator's eye: the
   badge sat under the switch at 390). The switch replaces the badge there. */
@media (max-width: 899px) { .topbar.has-modules .rc-badge { display: none; } .topbar.has-modules .topbar__left { min-width: 0; } }
/* T232 follow-up (the hub, 2026-09-07, the operator's word: a dropdown, not a strip):
   with a third and fourth level the switch is wider than a phone and pushed the
   language switch and the chip past the right edge (55 px at 390, 70 px at 375).
   On a phone the strip is hidden and one pill shows the level the person is in;
   a tap opens the other levels underneath it, the way the account chip opens its
   menu. shell.js paints the pill beside the strip; nothing leaves the screen. */
@media (max-width: 679px) {
  .topbar.has-modules .topbar__right { min-width: 0; flex: 1 1 auto; justify-content: flex-end; }
  .topbar.has-modules .bp-modules { border: 0; overflow: visible; margin-right: 4px; flex: none; }
  .topbar.has-modules .bp-modules > .bp-modules__m { display: none; }
  .topbar.has-modules .bp-modules__dd { display: block; }
}
.bp-modules__dd { display: none; position: relative; }
.bp-modules__cur { list-style: none; display: inline-flex; align-items: center; gap: 6px; height: 40px;
  padding: 0 10px 0 12px; border: 1px solid var(--bp-teal); border-radius: var(--r-md);
  background: var(--bp-teal); color: #fff; font-size: var(--t-eyebrow); font-weight: var(--w-semi);
  text-transform: uppercase; letter-spacing: var(--ls-caps); white-space: nowrap; cursor: pointer; }
.bp-modules__cur::-webkit-details-marker { display: none; }
.bp-modules__cur svg { width: 14px; height: 14px; transition: transform .15s; }
.bp-modules__dd[open] .bp-modules__cur svg { transform: rotate(180deg); }
.bp-modules__menu { position: absolute; top: calc(100% + 8px); right: 0; z-index: 70; min-width: 190px;
  padding: 6px; background: var(--paper); border: 1px solid var(--line); border-radius: var(--r-md);
  box-shadow: var(--sh-3); display: flex; flex-direction: column; }
.bp-modules__opt { display: flex; align-items: center; min-height: 44px; padding: 0 12px; border-radius: 8px;
  text-decoration: none; color: var(--ink); font-size: var(--t-sm); font-weight: var(--w-semi); white-space: nowrap; }
.bp-modules__opt:hover, .bp-modules__opt:focus-visible { background: var(--bp-teal-08); color: var(--bp-teal); outline: none; }
}

/* ---- the public shell (T219 phase B) ----
   No navigation: the content column sits under the topbar on its own, the
   same width the member pages use, and the footer closes it. */
.app--nonav .content { padding-top: var(--s-6); }
.app--nonav .content__inner { max-width: 760px; }

/* A note row in a dialog: the name of the group of fields under it, no input
   (T219 phase B fix round, the expert Edit dialog's six expertise boxes). */
.bp-field--note { margin-top: var(--s-2); }
.bp-field--note label { display: block; }
.bp-field--note small { display: block; color: var(--ink-3); }

/* ---- the grouped console sidebar (T266b, 2026-09-10) ------------------------
   The operator's fourth finding, on 2026-09-10, reading the admin console as an
   end user: "the left menu at a desk does not scroll on its own; the market feed
   entries and the rest are invisible until the page itself is scrolled to the
   bottom. It must be usable; group it" - a sidebar of Shopify quality.

   Measured before the change, on a 1440 x 900 desk: the sidebar's box is 836 px
   tall (`100dvh - --topbar-h`), its twenty rows are 918 px of list, and `.nav`
   carries no scroll of its own. So the last two entries (Market feed, Feed
   configuration) were below the fold of a box that is pinned to the viewport,
   and nothing a person could do inside the menu brought them back.

   Three things fix it, and all three are the shell's:

   1. THE SIDEBAR SCROLLS ITSELF. `.nav__list` was `height: 100%`, which pinned
      the list to the box and let its rows overflow into nothing; the list is now
      as tall as its rows and the sidebar scrolls them.
   2. IT IS GROUPED. shell.js draws the headings the layer declares (`groups` in
      app/shell/layers.js), so twenty entries read as five short lists.
   3. THE ROWS ARE ROWS. 44 px, the words as words rather than tracked capitals,
      and a gap between them, so the column reads as a menu and not as one slab
      of colour. The COLOURS are the house's and are untouched: slate for a row,
      teal for the row a person is on. Shopify is the reference for weight,
      spacing and grouping; it is not the reference for our palette.

   Scoped to `.nav--groups`, which shell.js sets only on a layer that declares
   groups. That matters for more than tidiness: the desktop sub-item flyout
   (`.nav__sub`) hangs OUTSIDE the sidebar's box at `left: 100%`, and an
   `overflow` on `.nav` would clip it. The three consoles that are grouped carry
   no sub-items at all; the member layer, which does, is untouched. */
@media (min-width: 900px) {
  .nav--groups {
    overflow-y: auto; overscroll-behavior: contain;
    scrollbar-width: thin; padding-bottom: var(--s-4);
  }
  .nav--groups .nav__list { height: auto; }
  .nav--groups .nav__item { height: auto; padding-inline: 8px; }
  .nav--groups .nav__item + .nav__item { margin-top: 2px; }
  .nav--groups .nav__link {
    min-height: 44px; height: auto; padding: 0 12px; gap: 10px;
    border-radius: var(--r-md);
    font-size: .82rem; font-weight: var(--w-med); letter-spacing: 0; text-transform: none;
  }
  /* the label can be two words long (Organisation users, Feed configuration)
     and reads as one line that ends in an ellipsis rather than a wrap */
  .nav--groups .nav__ico-label { flex-direction: row; gap: 10px; align-items: center; min-width: 0; }
  .nav--groups .nav__ico-label > span:last-child { min-width: 0; }
  /* the row a person is on: the house's teal, and the mark inside the rounded
     row rather than against the sidebar's own edge */
  .nav--groups .nav__item.is-active .nav__link { box-shadow: inset 3px 0 0 rgba(255, 255, 255, .92); }
  /* the group heading: quiet, above its rows, never a control. --ink-2 (6.75:1
     on the paper) and not --ink-3, which is 3.15:1 and would fail AA. */
  .nav--groups .nav__group { flex: 0 0 auto; padding: 18px 20px 6px; }
  .nav--groups .nav__group:first-child { padding-top: 10px; }
  .nav--groups .nav__group-h {
    font-size: var(--t-eyebrow); font-weight: var(--w-semi); text-transform: uppercase;
    letter-spacing: var(--ls-caps); color: var(--ink-2);
  }
}
/* Under 900 the menu is the horizontal strip the phone already has, and a
   heading has no place in a row of tabs: the strip is unchanged. */
@media (max-width: 899px) { .nav__group { display: none; } }
