/* Back office console (canvas "moneyOS_lean System Map", back office home 1b at line 675).
   Loaded after tokens.css and app.css: tokens.css is the single source of colour, type,
   space, radius, motion and size; app.css supplies the font faces, the control base and
   the eight interaction states. This sheet only adds the back-office layout and the
   places the canvas departs from the operator app. It defines zero custom properties and
   holds no literal colour, size, radius or duration. */

/* --- Page frame. The operator app centres a fixed column; the back office is a
       full-width desktop console with the canvas page gutter. --- */
body.backoffice main{width:100%;max-width:none;margin:0;padding:var(--space-28)}
body.backoffice .eyebrow{font-size:var(--text-sm)} /* canvas eyebrows are 13px, not the app's 12px */
body.backoffice h1{margin:0}
.bo-message:empty{display:none}
.bo-message{margin:0 0 var(--space-16);padding:var(--space-12) var(--space-16);border:1px solid var(--color-border-lead);border-radius:var(--radius-card);background:var(--color-feedback-error-bg);color:var(--color-feedback-error-text);font-size:var(--text-sm);max-width:none}

/* --- Top bar: 72px, brand square 34px, six tabs, language switch, user chip, sign-out. --- */
.bo-topbar{display:flex;align-items:center;gap:var(--space-20);height:var(--size-72);padding-inline:var(--space-28);background:var(--color-surface-card);border-bottom:1px solid var(--color-border-default)}
.bo-brand{display:flex;align-items:center;gap:var(--space-10);flex:0 0 auto}
.bo-mark{display:flex;align-items:center;justify-content:center;width:var(--size-34);height:var(--size-34);border-radius:var(--radius-card);background:var(--color-action-primary);color:var(--color-text-on-action);font-weight:var(--weight-bold);font-size:var(--text-base)}
.bo-brand-text{display:flex;flex-direction:column;line-height:var(--leading-tight)}
.bo-brand-name{font-weight:var(--weight-bold);font-size:var(--text-md);letter-spacing:-0.01em;color:var(--color-text-primary)}
.bo-brand-sub{font-size:var(--text-sm);letter-spacing:0.16em;color:var(--color-action-primary)}
/* Signed out, the console is not there to be operated; the brand and the language
   switch remain, exactly as the canvas draws the operator sign-in screen. */
body.backoffice:has(#workspace[hidden]) .bo-console,
body.backoffice:has(#workspace[hidden]) .bo-account{display:none}
.bo-console{display:flex;align-items:center;flex:1 1 auto;min-width:0}
.bo-tabs{display:flex;align-items:center;gap:var(--space-4);flex-wrap:wrap}
.bo-tabs button{display:inline-flex;align-items:center;gap:var(--space-8);height:var(--size-72);min-height:0;padding-inline:var(--space-14);border:0;border-bottom:2px solid transparent;border-radius:0;background:transparent;color:var(--color-text-secondary);font-size:var(--text-sm);font-weight:var(--weight-regular);white-space:nowrap}
.bo-tabs button:hover{background:var(--color-action-ghost-hover);color:var(--color-text-primary)}
.bo-tabs button:active{transform:none}
.bo-tabs button[aria-current=page]{color:var(--color-text-primary);font-weight:var(--weight-semibold);border-bottom-color:var(--color-action-primary)}
.bo-tabs button:focus-visible{border-radius:var(--radius-control)}
.bo-tab-badge:empty{display:none}
.bo-tab-badge{display:inline-flex;align-items:center;justify-content:center;min-width:var(--space-20);height:var(--space-20);padding-inline:var(--space-6);border-radius:var(--radius-pill);background:var(--color-badge-failed-bg);color:var(--color-badge-failed-text);font-size:var(--text-sm);font-weight:var(--weight-semibold);line-height:var(--leading-none)}

body.backoffice .language-switch{margin-left:auto;background:transparent;border-color:var(--color-border-strong)}
body.backoffice .language-switch button{height:var(--size-34)}
/* The canvas fills the active language with gold and writes on it in the on-accent ink;
   the operator app still fills it with the text colour (carried on ticket 14). */
body.backoffice .language-switch button[aria-pressed=true]{background:var(--color-action-primary);color:var(--color-text-on-action)}

.bo-account{display:flex;align-items:center;gap:var(--space-12);flex:0 0 auto}
.bo-user{display:inline-flex;align-items:center;gap:var(--space-10);font-size:var(--text-sm);color:var(--color-text-secondary)}
body.backoffice .avatar{width:var(--size-34);height:var(--size-34);border:1px solid var(--color-border-idle);background:var(--color-surface-sunken);color:var(--color-action-primary)}
.bo-icon-button{display:inline-flex;align-items:center;justify-content:center;width:var(--size-34);height:var(--size-34);min-height:0;padding:0;border:1px solid var(--color-border-default);border-radius:var(--radius-control);background:transparent;color:var(--color-text-secondary)}
.bo-icon-button:hover{background:var(--color-action-ghost-hover);border-color:var(--color-border-strong);color:var(--color-text-primary)}

/* --- Page head: eyebrow, 30px title, search field, primary action. --- */
.bo-page-head{display:flex;align-items:flex-end;gap:var(--space-16);flex-wrap:wrap}
.bo-page-title{display:flex;flex-direction:column;gap:var(--space-6);min-width:0}
.bo-page-title h1{display:flex;align-items:baseline;gap:var(--space-8);flex-wrap:wrap}
.bo-count{color:var(--color-text-secondary);font-weight:var(--weight-regular)}
.bo-search{display:inline-flex;align-items:center;flex:0 1 auto;flex-direction:row;gap:var(--space-10);margin-left:auto;min-width:var(--size-280);height:var(--size-44);padding-inline:var(--space-14);border:1px solid var(--color-border-strong);border-radius:var(--radius-control);background:var(--color-surface-card);color:var(--color-text-caption);font-size:var(--text-sm);font-weight:var(--weight-regular)}
.bo-search input{min-height:0;height:100%;border:0;padding:0;background:transparent;color:var(--color-text-primary);font-size:var(--text-sm)}
.bo-search input::placeholder{color:var(--color-text-caption);opacity:1}
.bo-search:has(input:focus-visible){outline:2px solid var(--color-focus-ring);outline-offset:2px;box-shadow:var(--shadow-focus-ring)}
.bo-search input:focus-visible{outline:none;box-shadow:none}
.bo-primary{display:inline-flex;align-items:center;gap:var(--space-8);height:var(--size-44);min-height:var(--size-44);padding-inline:var(--space-18);border-radius:var(--radius-control);font-size:var(--text-sm);font-weight:var(--weight-semibold)}

/* --- Four summary tiles; the problem tile is brick-bordered on a brick wash. --- */
.bo-tiles{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:var(--space-16);margin-top:var(--space-24)}
.bo-tile{display:flex;flex-direction:column;gap:var(--space-10);padding:var(--space-20);border:1px solid var(--color-border-default);border-radius:var(--radius-card-lg);background:var(--color-surface-card);min-width:0}
.bo-tile-label{font-size:var(--text-sm);color:var(--color-text-secondary)}
.bo-tile-value{font-size:var(--text-xxl);font-weight:var(--weight-semibold);line-height:var(--leading-none)}
.bo-tile-value-accent{color:var(--color-action-primary)}
.bo-tile-note{font-size:var(--text-sm);font-weight:var(--weight-regular);color:var(--color-text-caption)}
.bo-tile-problem{border-color:var(--color-border-danger);background:var(--color-surface-problem)}
.bo-tile-value-problem{color:var(--color-feedback-error-text)}
.bo-tile-problem .bo-tile-note{color:var(--color-text-secondary)}

/* --- Company cards. --- */
.bo-cards{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--space-16);margin-top:var(--space-16);align-items:stretch}
.bo-card{display:flex;flex-direction:column;gap:var(--space-14);padding:var(--space-20);border:1px solid var(--color-border-default);border-radius:var(--radius-card-lg);background:var(--color-surface-card);min-width:0}
.bo-card-problem{border-color:var(--color-border-danger);background:var(--color-surface-lead)}
.bo-card-draft{border:1px dashed var(--color-border-idle);background:var(--color-surface-draft)}
.bo-card-head{display:flex;align-items:flex-start;gap:var(--space-12)}
.bo-card-id{min-width:0}
.bo-card-name{font-size:var(--text-label);font-weight:var(--weight-semibold);line-height:var(--leading-snug)}
.bo-card-draft .bo-card-name{color:var(--color-text-secondary)}
.bo-card-meta{font-size:var(--text-sm);color:var(--color-text-caption);font-family:var(--font-mono)}
.bo-card-meta-plain{font-family:var(--font-sans)}
.bo-pill{display:inline-flex;align-items:center;margin-left:auto;height:var(--size-26);padding-inline:var(--space-10);border:1px solid var(--color-border-idle);border-radius:var(--radius-pill);background:var(--color-surface-sunken);color:var(--color-text-secondary);font-size:var(--text-sm);font-weight:var(--weight-semibold);white-space:nowrap}
.bo-pill-problem{border-color:var(--color-border-danger);background:var(--color-feedback-error-bg);color:var(--color-feedback-error-text)}
.bo-pill-draft{border-style:dashed;background:transparent}

.bo-stats{display:flex;gap:var(--space-8)}
.bo-stat{display:flex;flex:1 1 0;flex-direction:column;gap:var(--space-4);padding:var(--space-10);border:1px solid var(--color-border-default);border-radius:var(--radius-card);min-width:0}
.bo-stat-label{font-size:var(--text-sm);color:var(--color-text-caption)}
.bo-stat-value{font-size:var(--text-sm);font-weight:var(--weight-semibold)}
.bo-stat-problem{border-color:var(--color-border-danger);background:var(--color-surface-problem-soft)}
.bo-stat-problem .bo-stat-label{color:var(--color-text-secondary)}
.bo-stat-problem .bo-stat-value{color:var(--color-feedback-error-text)}

.bo-meter-head{display:flex;justify-content:space-between;gap:var(--space-8);font-size:var(--text-sm);color:var(--color-text-secondary)}
.bo-meter{margin-top:var(--space-8);height:var(--space-6);border-radius:var(--radius-bar);background:var(--color-meter-track);overflow:hidden}
.bo-meter-fill{height:var(--space-6);border-radius:var(--radius-bar);background:var(--color-meter-fill)}
.bo-meter-fill-problem{background:var(--color-meter-fill-problem)}

.bo-checklist{display:flex;flex-direction:column;gap:var(--space-8)}
.bo-check{display:flex;align-items:center;gap:var(--space-10);font-size:var(--text-sm);color:var(--color-text-caption)}
.bo-check-done{color:var(--color-text-secondary)}
.bo-check-mark{display:inline-flex;align-items:center;justify-content:center;width:var(--space-20);height:var(--space-20);border:1px solid var(--color-border-idle);border-radius:var(--radius-pill);flex:0 0 auto}
.bo-check-done .bo-check-mark{border-color:transparent;background:var(--color-surface-accent-chip);color:var(--color-action-primary)}

.bo-card-foot{display:flex;align-items:center;justify-content:space-between;gap:var(--space-12);margin-top:auto;padding-top:var(--space-12);border-top:1px solid var(--color-border-default);font-size:var(--text-sm)}
.bo-card-foot-note{color:var(--color-text-secondary)}
.bo-card-foot a{color:var(--color-text-link);font-weight:var(--weight-semibold);text-decoration:none}
.bo-card-foot a:hover{text-decoration:underline}

/* TICKET 184: the dashed "open a new company" card that closed the list is gone; the page
   head's button is the one way in (its rules, .bo-new-card and ticket 112's ink, left with it). */

.bo-no-match{margin-top:var(--space-16);color:var(--color-text-secondary)}

/* --- Panels other than the home tab, and the new-company empty state. --- */
.bo-empty{margin-top:var(--space-24);padding:var(--space-40) var(--space-28);border:1px solid var(--color-border-default);border-radius:var(--radius-card-lg);background:var(--color-surface-card)}
.bo-empty h1,.bo-empty h2{font-size:var(--text-xxl);font-weight:var(--weight-semibold);letter-spacing:-0.02em;line-height:var(--leading-tight);margin:0 0 var(--space-8)}
.bo-denied{max-width:560px;margin:var(--space-36) auto;padding:clamp(var(--space-20),5vw,var(--space-40));border:1px solid var(--color-border-lead);border-radius:var(--radius-card);background:var(--color-surface-lead)}
.bo-denied h1{margin:var(--space-6) 0 var(--space-8);color:var(--color-feedback-error-text)}

/* --- The reason gate. One component, exported from backoffice.js, mounted wherever a
       later ticket needs a write; the primary button is held until a reason is typed. --- */
.bo-gate{display:flex;align-items:center;flex-wrap:wrap;gap:var(--space-14);margin-top:var(--space-16);padding:var(--space-16) var(--space-20);border:var(--size-hairline-strong) solid var(--color-action-primary);border-radius:var(--radius-card-lg);background:var(--color-surface-selected)}
.bo-gate-text{display:flex;flex-direction:column;gap:var(--space-4);min-width:0;flex:0 1 auto}
.bo-gate-title{font-size:var(--text-label);font-weight:var(--weight-semibold);color:var(--color-action-primary)}
.bo-gate-note{font-size:var(--text-sm);color:var(--color-text-secondary)}
.bo-gate label{flex:1 1 var(--size-280);min-width:0;flex-direction:row;align-items:center}
.bo-gate input{height:var(--size-44);min-height:var(--size-44);border-color:var(--color-border-idle);background:var(--color-surface-field);font-size:var(--text-sm)}
.bo-gate input::placeholder{color:var(--color-text-caption);opacity:1}
.bo-gate button{height:var(--size-44);min-height:var(--size-44);padding-inline:var(--space-18);border-radius:var(--radius-control);font-size:var(--text-sm);font-weight:var(--weight-semibold);flex:0 0 auto}
/* Disabled is drawn, not faded: the canvas fills a held button with a flat grey. The
   canvas pair, tertiary ink on the idle outline grey, measured 3.22:1, so the fill drops
   to the sunken surface and the canvas grey becomes the outline: that pair is 5.10:1. */
.bo-gate button:disabled{background:var(--color-action-disabled-bg);border-color:var(--color-action-disabled-border);color:var(--color-action-disabled-text);opacity:1;cursor:not-allowed}
.bo-gate-result:empty{display:none}
.bo-gate-result{flex:1 1 100%;margin:0;font-size:var(--text-sm);color:var(--color-text-secondary)}

/* --- Narrower desktops. The canvas designs the console at 1440 and the README says a
       phone layout is not designed; these two steps keep it usable rather than broken. --- */
@media (max-width: 1200px){
  .bo-tiles{grid-template-columns:repeat(2,minmax(0,1fr))}
  .bo-cards{grid-template-columns:repeat(2,minmax(0,1fr))}
}
@media (max-width: 860px){
  .bo-topbar{height:auto;flex-wrap:wrap;padding-block:var(--space-12);row-gap:var(--space-8)}
  .bo-tabs button{height:var(--size-48)}
  .bo-tiles,.bo-cards{grid-template-columns:minmax(0,1fr)}
  .bo-search{margin-left:0;min-width:0;width:100%}
}

/* ===========================================================================
   TICKET 20 BEGIN - B5 ปริมาณการใช้งาน, B6 ผู้ใช้และสิทธิ์, B7 Audit log
   (canvas frames at lines 1128, 1194 and 1229). Same three-size type scale, same
   tokens; the only new shapes are the month chips, the bar chart and the three
   tables. Nothing above this line is changed by this ticket.
   =========================================================================== */

.bo-chips,.bo-filters{display:flex;align-items:flex-end;gap:var(--space-8);margin-left:auto;flex-wrap:wrap}
.bo-chip{height:var(--size-36);min-height:var(--size-36);padding-inline:var(--space-14);border:1px solid var(--color-border-strong);border-radius:var(--radius-control);background:transparent;color:var(--color-text-secondary);font-size:var(--text-sm);font-weight:var(--weight-semibold)}
.bo-chip:hover{background:var(--color-action-ghost-hover);color:var(--color-text-primary);border-color:var(--color-border-strong)}
/* Selected is the canvas's gold fill with the on-accent ink; it is the same pair the
   language switch uses, so one selected thing on this page looks like every other. */
.bo-chip[aria-pressed=true]{background:var(--color-action-primary);border-color:var(--color-action-primary);color:var(--color-text-on-action)}
.bo-chip[aria-pressed=true]:hover{background:var(--color-action-primary-hover);border-color:var(--color-action-primary-hover)}

.bo-panel-message:empty{display:none}
.bo-panel-message{margin:var(--space-16) 0 0;padding:var(--space-12) var(--space-16);border:1px solid var(--color-border-lead);border-radius:var(--radius-card);background:var(--color-feedback-error-bg);color:var(--color-feedback-error-text);font-size:var(--text-sm)}

/* The note under each page: the retention rule, the domain rule, the append-only rule. */
.bo-note{margin:var(--space-14) 0 0;padding:var(--space-12) var(--space-14);border:1px solid var(--color-border-default);border-radius:var(--radius-card);font-size:var(--text-sm);color:var(--color-text-secondary)}

/* --- B5: the six-month bar chart. Every colour is a CSS class on the SVG node, never
       an attribute on it: `fill`/`stroke` are `currentColor` and the class sets `color`,
       so the chart cannot drift from the theme. --- */
.bo-chart-card{margin-top:var(--space-16);padding:var(--space-20);border:1px solid var(--color-border-default);border-radius:var(--radius-card-lg);background:var(--color-surface-card)}
.bo-card-title-row{display:flex;align-items:baseline;gap:var(--space-12)}
.bo-card-title-row h2{margin:0;font-size:var(--text-label);font-weight:var(--weight-semibold);line-height:var(--leading-snug)}
.bo-card-title-note{margin-left:auto;font-size:var(--text-sm);color:var(--color-text-secondary)}
.bo-chart svg{display:block;width:100%;height:auto;margin-top:var(--space-14)}
.bo-chart text{fill:currentColor;font-size:var(--text-sm)}
.bo-chart line{stroke:currentColor}
.bo-chart-grid{color:var(--color-chart-grid)}
.bo-chart-axis{color:var(--color-chart-axis)}
.bo-chart-bar{fill:currentColor;color:var(--color-border-idle)}
.bo-chart-bar-current{color:var(--color-chart-series-1)}
.bo-chart-tick,.bo-chart-label{color:var(--color-text-secondary)}
.bo-chart-label-current{color:var(--color-text-primary);font-weight:var(--weight-semibold)}

/* --- The three tables. app.css already draws the scroller, the sunken header row and
       the row rule; the canvas asks for the caption size throughout and a caption-coloured header. --- */
/* `position:relative` is load-bearing: the visually hidden column label in the users
   table is absolutely positioned, and with a static scroller its containing block is
   the page itself, so it escapes the horizontal scroll and gives the whole document a
   scrollbar at phone width, which verify_responsive measures and fails. */
body.backoffice .table-scroll{position:relative;margin:var(--space-16) 0 0;border-radius:var(--radius-card-lg)}
/* TICKET 135: this is the rule that actually wins every table header's text colour --
   `body.backoffice th` (0,1,2) beats both `.bo-table th` and `.bo-table-frame th`
   (0,1,1) on specificity alone, so its color is what axe_audit measured on the ticket
   96 harness's `#bo-b1-accounts thead th` (a table styled only by `.bo-table-frame`,
   never `.bo-table`) and what every OTHER console table header renders too, whichever
   of the two wrapping classes it sits in. color-text-caption on surface-sunken
   measures 4.39:1 (scripts/contrast.py), under WCAG AA's 4.5:1 for normal text.
   color-text-secondary on the same surface measures 6.87:1 and is the nearest text
   token that clears it, so every header in the console darkens with it, in this one
   rule. */
body.backoffice th{color:var(--color-text-secondary);font-size:var(--text-sm);font-weight:var(--weight-regular)}
body.backoffice td{font-size:var(--text-sm);vertical-align:middle}
body.backoffice tbody tr:last-child td{border-bottom:0}
.bo-mono{font-family:var(--font-mono)}
.bo-muted{color:var(--color-text-secondary)}
.bo-strong{font-weight:var(--weight-semibold)}
.bo-behind{color:var(--color-feedback-error-text)}
.bo-empty-row{color:var(--color-text-secondary)}

/* --- B6: the user cell, the role pill and the edit affordance. --- */
.bo-user-cell{display:flex;align-items:center;gap:var(--space-10);min-width:0}
body.backoffice .bo-user-cell .avatar{width:var(--space-28);height:var(--space-28);border:1px solid var(--color-border-idle);color:var(--color-text-secondary)}
body.backoffice .bo-user-cell .bo-avatar-lead{color:var(--color-action-primary)}
.bo-role-pill{display:inline-flex;align-items:center;height:var(--space-24);padding-inline:var(--space-10);border:1px solid var(--color-border-idle);border-radius:var(--radius-pill);font-size:var(--text-sm);font-weight:var(--weight-semibold);white-space:nowrap}
.bo-role-pill-lead{border-color:transparent;background:var(--color-surface-accent-chip);color:var(--color-action-primary)}
/* TICKET 167: the super-admin's badge, a shield and "System owner", ahead of any company role. */
.bo-role-pill-system{gap:var(--space-4);margin-inline-end:var(--space-4)}
.bo-role-pill-system .icon{flex:none}
/* The icon moves an inline-flex box's baseline, so the badge and the company role beside it
   are both centred on the line rather than sitting on two different baselines. */
.bo-role-pill-system,.bo-role-pill-system + .bo-role-pill{vertical-align:middle}
.bo-edit-cell{text-align:right}
/* TICKET 196: the disabled "Edit" of ticket 20 and the three role cards are gone; what each
   role can do is a disclosure under the list now (`.bo-users-help`). */

/* --- B7: the three filter selects and the CSV download. --- */
.bo-filter{flex:0 0 auto;min-width:0}
body.backoffice .bo-filter select{height:var(--size-40);min-height:var(--size-40);min-width:var(--size-150);inline-size:auto;padding-inline:var(--space-14);border-color:var(--color-border-strong);background:transparent;font-size:var(--text-sm)}
body.backoffice .bo-filter select:hover{background:var(--color-action-ghost-hover)}
#bo-audit-csv{height:var(--size-40);min-height:var(--size-40);padding-inline:var(--space-16);font-size:var(--text-sm);font-weight:var(--weight-semibold)}

@media (max-width: 860px){
  .bo-chips,.bo-filters{margin-left:0;width:100%}
}

/* A change is one line per value that moved: its label above, the arrow between the two
   values. The label is the caption colour so the values lead. */
.bo-change+.bo-change{margin-top:var(--space-6)}
.bo-change-label{display:block;color:var(--color-text-caption)}

/* =========================== TICKET 20 END ================================ */
/* --- ticket 19 begin: B3 สุขภาพระบบ and B4 ศูนย์แจ้งเตือน (canvas lines 976 and 1050).
       Appended as one block so the three tickets working on this sheet in parallel
       merge mechanically. Same rules as the sheet above: tokens only, no literal
       colour, size, radius or duration, and every state drawn rather than faded. --- */

.bo-head-note{margin:0 0 0 auto;font-size:var(--text-sm);color:var(--color-text-caption);text-align:end}
.bo-panel-note{margin:var(--space-16) 0 0;padding:var(--space-10) var(--space-12);border:1px solid var(--color-border-default);border-radius:var(--radius-card);font-size:var(--text-sm);color:var(--color-text-secondary)}
.bo-panel-note:empty{display:none}
.bo-panel-card{padding:var(--space-20);border:1px solid var(--color-border-default);border-radius:var(--radius-card-lg);background:var(--color-surface-card);min-width:0}
.bo-panel-card h2{margin:0;font-size:var(--text-label);font-weight:var(--weight-semibold);line-height:var(--leading-snug)}

/* Status dot. The canvas draws the idle one in the outline grey (1.39:1 on the card);
   it carries meaning here, so it takes the caption colour and keeps its 5.3:1. */
.bo-dot{display:inline-block;flex:0 0 auto;width:var(--space-10);height:var(--space-10);border-radius:var(--radius-pill);background:var(--color-text-caption)}
.bo-dot-ok{background:var(--color-action-primary)}
.bo-dot-problem{background:var(--color-border-danger)}

/* --- B3: three status cards, then the 1fr / 1.35fr split. --- */
.bo-health-cards{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--space-16);margin-top:var(--space-20)}
.bo-health-card{display:flex;flex-direction:column;padding:var(--space-20);border:1px solid var(--color-border-default);border-radius:var(--radius-card-lg);background:var(--color-surface-card);min-width:0}
.bo-health-card-problem{border-color:var(--color-border-danger);background:var(--color-surface-lead)}
.bo-health-head{display:flex;align-items:center;gap:var(--space-10)}
.bo-health-name{font-size:var(--text-label);font-weight:var(--weight-semibold);line-height:var(--leading-snug)}
.bo-health-figure{display:flex;align-items:baseline;gap:var(--space-6);margin-top:var(--space-14);font-size:var(--text-xxl);font-weight:var(--weight-semibold);line-height:var(--leading-none);flex-wrap:wrap}
.bo-health-figure-problem{color:var(--color-feedback-error-text)}
.bo-health-unit{font-size:var(--text-sm);font-weight:var(--weight-regular);color:var(--color-text-secondary)}
.bo-facts{display:flex;flex-direction:column;gap:var(--space-8);margin-top:var(--space-14);font-size:var(--text-sm);color:var(--color-text-secondary)}
.bo-fact{display:flex;justify-content:space-between;gap:var(--space-12)}
.bo-fact-value{color:var(--color-text-primary);text-align:end;min-width:0;overflow-wrap:anywhere}

.bo-health-split{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.35fr);gap:var(--space-16);margin-top:var(--space-16);align-items:start}
.bo-services{display:flex;flex-direction:column;gap:var(--space-10);margin-top:var(--space-14);font-size:var(--text-sm)}
.bo-service{display:flex;align-items:center;gap:var(--space-10)}
.bo-service .bo-dot{width:var(--space-8);height:var(--space-8)}
.bo-service-unit{flex:1 1 auto;min-width:0;font-family:var(--font-mono);overflow-wrap:anywhere}
.bo-service-state{color:var(--color-text-secondary);white-space:nowrap}
.bo-restart{display:flex;flex-direction:column;align-items:flex-start;gap:var(--space-8);margin-top:var(--space-16)}
.bo-restart button{height:var(--size-40);min-height:var(--size-40);padding-inline:var(--space-16);font-size:var(--text-sm);font-weight:var(--weight-semibold)}
/* Held, not faded: the same treatment the reason gate's own button gets, so the
   refusal stays readable (opacity 0.5 on this pair measures below AA). */
.bo-restart button:disabled{background:var(--color-action-disabled-bg);border-color:var(--color-action-disabled-border);color:var(--color-action-disabled-text);opacity:1;cursor:not-allowed}
.bo-restart .bo-panel-note{margin-top:0}

.bo-table-frame{margin-top:var(--space-14);border:1px solid var(--color-border-default);border-radius:var(--radius-card);overflow:hidden}
.bo-table{width:100%;border-collapse:collapse;font-size:var(--text-sm)}
.bo-table th{padding:var(--space-8) var(--space-12);background:var(--color-surface-sunken);color:var(--color-text-caption);font-weight:var(--weight-regular);text-align:start;white-space:nowrap}
.bo-table td{padding:var(--space-10) var(--space-12);border-top:1px solid var(--color-border-default);text-align:start;overflow-wrap:anywhere}
.bo-table tbody th{border-top:1px solid var(--color-border-default);background:transparent;color:var(--color-text-primary);font-weight:var(--weight-semibold)}
.bo-table-row-problem td,.bo-table-row-problem th{background:var(--color-surface-problem-soft)}
.bo-cell-problem{color:var(--color-feedback-error-text)}
.bo-cell-quiet{color:var(--color-text-secondary)}

/* --- B4: filter chips, then the 1.25fr / 1fr split. --- */
.bo-chips{display:flex;align-items:center;gap:var(--space-8);margin-left:auto;flex-wrap:wrap}
.bo-chips button{display:inline-flex;align-items:center;gap:var(--space-6);height:var(--size-36);min-height:var(--size-36);padding-inline:var(--space-14);border:1px solid var(--color-border-strong);border-radius:var(--radius-pill);background:transparent;color:var(--color-text-secondary);font-size:var(--text-sm);font-weight:var(--weight-semibold)}
.bo-chips button:hover{background:var(--color-action-ghost-hover);color:var(--color-text-primary)}
.bo-chips button[aria-pressed=true]{background:var(--color-action-primary);border-color:var(--color-action-primary);color:var(--color-text-on-action)}
.bo-chips button[aria-pressed=true]:hover{background:var(--color-action-primary-hover);border-color:var(--color-action-primary-hover)}
.bo-chip-count:empty{display:none}

.bo-alert-split{display:grid;grid-template-columns:minmax(0,1.25fr) minmax(0,1fr);gap:var(--space-16);margin-top:var(--space-20);align-items:start}
.bo-alert-card{padding:var(--space-0);overflow:hidden}
.bo-alert-empty{margin:var(--space-20);border:0;padding:var(--space-0)}
.bo-alert-day{padding:var(--space-14) var(--space-18);border-bottom:1px solid var(--color-border-default);font-size:var(--text-sm);color:var(--color-text-caption)}
.bo-alert-day+.bo-alert-row{border-top:0}
.bo-alert-row{display:block;width:100%;min-height:0;padding:var(--space-16) var(--space-18);border:0;border-top:1px solid var(--color-border-default);border-left:var(--size-marker) solid transparent;border-radius:var(--space-0);background:transparent;color:var(--color-text-primary);font-weight:var(--weight-regular);text-align:start;white-space:normal}
.bo-alert-row:hover{background:var(--color-action-ghost-hover)}
.bo-alert-row:active{transform:none}
.bo-alert-row-active{border-left-color:var(--color-border-danger)}
.bo-alert-row[aria-current=true]{background:var(--color-surface-sunken)}
.bo-alert-row-active[aria-current=true]{background:var(--color-surface-problem)}
.bo-alert-head{display:flex;align-items:center;gap:var(--space-10);font-size:var(--text-sm)}
.bo-alert-company{font-weight:var(--weight-semibold)}
.bo-alert-time{color:var(--color-text-caption);font-family:var(--font-mono)}
.bo-alert-state{display:inline-flex;align-items:center;margin-left:auto;height:var(--space-24);padding-inline:var(--space-10);border:1px solid var(--color-border-idle);border-radius:var(--radius-pill);color:var(--color-text-secondary);font-weight:var(--weight-semibold);white-space:nowrap}
.bo-alert-state-active{border-color:var(--color-border-danger);color:var(--color-feedback-error-text)}
.bo-alert-row-active[aria-current=true] .bo-alert-state-active{border-color:var(--color-badge-failed-bg);background:var(--color-badge-failed-bg);color:var(--color-badge-failed-text)}
.bo-alert-text{margin-top:var(--space-8);font-size:var(--text-sm);line-height:var(--leading-normal)}
.bo-alert-row-cleared .bo-alert-text{color:var(--color-text-secondary)}

.bo-alert-side{display:flex;flex-direction:column;gap:var(--space-16);min-width:0}
.bo-detail-eyebrow{font-size:var(--text-sm);color:var(--color-text-caption)}
.bo-detail-key{margin-top:var(--space-6);font-size:var(--text-label);font-weight:var(--weight-semibold);line-height:var(--leading-snug);overflow-wrap:anywhere}
.bo-detail-line{margin-top:var(--space-12);font-size:var(--text-sm);line-height:var(--leading-normal);color:var(--color-text-secondary)}
.bo-detail-facts{margin-top:var(--space-16)}

/* The action card: 1.5px gold on the gold wash, with the shared reason gate inside it
   rather than beside it, so one component still holds every write on this page. */
.bo-action-card{padding:var(--space-20);border:var(--size-hairline-strong) solid var(--color-action-primary);border-radius:var(--radius-card-lg);background:var(--color-surface-selected);min-width:0}
.bo-action-title{margin:0;font-size:var(--text-label);font-weight:var(--weight-semibold);line-height:var(--leading-snug);color:var(--color-action-primary)}
.bo-action-row{display:flex;flex-wrap:wrap;gap:var(--space-8);margin-top:var(--space-12)}
/* The canvas leaves these two outlined actions transparent on the gold wash; they carry
   the panel fill instead, so the pair under the text is a real colour and the state gate
   measures it rather than reading the wash as solid gold. The difference on screen is the
   8% wash behind one outlined control. */
.bo-action-row a,.bo-action-row button{display:inline-flex;align-items:center;justify-content:center;height:var(--size-40);min-height:var(--size-40);padding-inline:var(--space-16);border:1px solid var(--color-border-strong);border-radius:var(--radius-control);background:var(--color-surface-card);color:var(--color-text-primary);font-size:var(--text-sm);font-weight:var(--weight-semibold);text-decoration:none;white-space:nowrap}
.bo-action-row a:hover,.bo-action-row button:hover{background:var(--color-action-ghost-hover);border-color:var(--color-border-strong);color:var(--color-text-primary)}
.bo-action-row .bo-action-primary{background:var(--color-action-primary);border-color:var(--color-action-primary);color:var(--color-text-on-action)}
.bo-action-row .bo-action-primary:hover{background:var(--color-action-primary-hover);border-color:var(--color-action-primary-hover);color:var(--color-text-on-action)}
.bo-action-row .bo-action-primary:disabled{background:var(--color-action-disabled-bg);border-color:var(--color-action-disabled-border);color:var(--color-action-disabled-text);opacity:1;cursor:not-allowed}
.bo-action-card .bo-gate{flex-direction:column;align-items:stretch;gap:var(--space-8);margin-top:var(--space-14);padding:var(--space-0);border:0;border-radius:var(--space-0);background:transparent}
.bo-action-card .bo-gate-note:empty{display:none}
.bo-action-card .bo-gate label{flex:1 1 auto}
.bo-action-denied{margin:var(--space-8) 0 0;font-size:var(--text-sm);color:var(--color-text-secondary)}
.bo-action-empty{margin:var(--space-12) 0 0;font-size:var(--text-sm);color:var(--color-text-secondary)}

/* Narrower desktops, as above: not a designed phone layout, just not a broken one. */
@media (max-width: 1200px){
  .bo-health-cards{grid-template-columns:repeat(2,minmax(0,1fr))}
  .bo-health-split,.bo-alert-split{grid-template-columns:minmax(0,1fr)}
}
@media (max-width: 860px){
  .bo-health-cards{grid-template-columns:minmax(0,1fr)}
  .bo-head-note{margin-left:0;text-align:start}
  .bo-chips{margin-left:0}
  /* The top bar's user chip is the one part of the console that still overflowed the
     narrowest width verify_responsive checks, on the shell as committed. It is not this
     ticket's element, so it is let go of here rather than restyled: the chip may shrink
     and the name may wrap. */
  .bo-account{flex:1 1 auto;min-width:0}
  .bo-user{min-width:0}
  #bo-user-name{min-width:0;overflow-wrap:anywhere;white-space:normal}
}
/* --- ticket 19 end --- */
/* ===== Ticket 18: B1, the company detail. Everything this ticket adds to this sheet
   lives between this line and the matching end marker. It is appended, so its two
   narrow-width rules extend the fallback above rather than editing it. ========= */

/* --- B1, the company detail (canvas frame B1, line 846). Opened in place from a card:
       breadcrumb, head, four tiles, a 2:1 split, and the reason gate at the foot. --- */
.bo-card{cursor:pointer}
.bo-card-draft,.bo-card:has(.bo-manage:focus-visible){cursor:default}
.bo-manage{height:auto;min-height:0;padding:0;border:0;border-radius:var(--radius-sm);background:transparent;color:var(--color-text-link);font-size:var(--text-sm);font-weight:var(--weight-semibold)}
.bo-manage:hover{background:transparent;border-color:transparent;text-decoration:underline}
.bo-manage:active{transform:none}

.bo-crumb{display:flex;align-items:baseline;gap:var(--space-6);font-size:var(--text-sm);color:var(--color-text-caption)}
.bo-crumb-link,.bo-quiet-link{height:auto;min-height:0;padding:0;border:0;border-radius:var(--radius-sm);background:transparent;color:var(--color-text-link);font-size:var(--text-sm);font-weight:var(--weight-semibold)}
.bo-crumb-link:hover,.bo-quiet-link:hover{background:transparent;border-color:transparent;text-decoration:underline}
.bo-crumb-link:active,.bo-quiet-link:active{transform:none}
.bo-quiet-link{display:inline-flex;align-items:baseline;gap:var(--space-4);margin-left:auto}

.bo-b1-head{display:flex;align-items:center;gap:var(--space-14);flex-wrap:wrap;margin-top:var(--space-8)}
.bo-b1-head h1{font-size:var(--text-xxl);font-weight:var(--weight-semibold);letter-spacing:-0.02em;line-height:var(--leading-tight)}
.bo-pill-inline{margin-left:0}
.bo-b1-meta{font-size:var(--text-sm);color:var(--color-text-caption);font-family:var(--font-mono);min-width:0;overflow-wrap:anywhere}
.bo-b1-action{height:var(--size-40);min-height:var(--size-40);padding-inline:var(--space-16);border-radius:var(--radius-control);font-size:var(--text-sm);font-weight:var(--weight-semibold)}
/* app.css hovers .danger onto the brick wash, an alpha fill. verify_states composites a
   translucent background by dropping its alpha, so it reads that hover as brick text on
   solid brick, 1.78:1, where WCAG 1.4.3 needs 4.5:1. The console's destructive control
   hovers onto the opaque sunken surface instead: the same darkening, nothing for a gate or
   a rendering engine to read two ways. Accessibility over the canvas, which draws only the
   resting state of this button. */
.bo-b1-action.danger:hover{background:var(--color-surface-sunken);border-color:var(--color-action-destructive-border)}
.bo-tile-value-small{font-size:var(--text-label);line-height:var(--leading-snug)}
#bo-b1-meter[hidden]{display:none}

.bo-split{display:grid;grid-template-columns:minmax(0,2fr) minmax(0,1fr);gap:var(--space-16);margin-top:var(--space-16);align-items:start}
.bo-col{display:flex;flex-direction:column;gap:var(--space-16);min-width:0}
.bo-b1-card{padding:var(--space-20);border:1px solid var(--color-border-default);border-radius:var(--radius-card-lg);background:var(--color-surface-card);min-width:0}
.bo-b1-card-head{display:flex;align-items:baseline;gap:var(--space-12)}
.bo-b1-card h2{margin:0;font-size:var(--text-label);font-weight:var(--weight-semibold);line-height:var(--leading-snug)}

.bo-fields{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--space-14);margin-top:var(--space-14)}
.bo-field{display:flex;flex-direction:column;gap:var(--space-4);min-width:0}
.bo-field-label{font-size:var(--text-sm);color:var(--color-text-caption)}
.bo-field-value{font-size:var(--text-sm);min-width:0;overflow-wrap:anywhere}
.bo-mono{font-family:var(--font-mono)}
/* app.css gives every label a flex basis meant for a form column. Inside this field block,
 * whose direction is column, that basis lands on the height instead of the width and the
 * switch grows to it. The switch sizes itself. */
.bo-switch{flex:0 0 auto;flex-direction:row;align-items:center;gap:var(--space-8);font-size:var(--text-sm);color:var(--color-text-secondary)}
.bo-switch input{width:var(--space-20);height:var(--space-20);min-height:0;accent-color:var(--color-action-primary);flex:0 0 auto}

.bo-note{margin:var(--space-14) 0 0;padding:var(--space-10) var(--space-12);border:1px solid var(--color-border-default);border-radius:var(--radius-card);font-size:var(--text-sm);color:var(--color-text-secondary)}
.bo-note-plain{border:0;padding:0;margin-top:var(--space-12)}
/* TICKET 168: the slip reader card's "this company kept its own reader" sentence sits inside
   the card's field grid and reads across it, not squeezed into one column. */
.bo-fields > .bo-note-plain{grid-column:1 / -1;margin-top:0}
/* TICKET 171: the image test's line names every reader of the chain, so it reads across the card. */
.bo-fields > .bo-field-wide{grid-column:1 / -1}
.bo-refused{margin:var(--space-14) 0 0;font-size:var(--text-sm);color:var(--color-text-secondary)}

.bo-table-frame{margin-top:var(--space-14);border:1px solid var(--color-border-default);border-radius:var(--radius-card);overflow:auto}
.bo-table-frame table{min-width:0}
.bo-table-frame th,.bo-table-frame td{padding:var(--space-10) var(--space-12);border-bottom:0;font-size:var(--text-sm);vertical-align:middle}
.bo-table-frame th{background:var(--color-surface-sunken);color:var(--color-text-caption);font-weight:var(--weight-regular)}
.bo-table-frame tbody tr{border-top:1px solid var(--color-border-default)}
.bo-row-draft td{color:var(--color-text-secondary)}
.bo-used{color:var(--color-action-primary)}
.bo-used-over{color:var(--color-feedback-error-text)}
.bo-pill-row{display:inline-flex;align-items:center;height:var(--size-24);padding-inline:var(--space-8);border:1px solid var(--color-border-idle);border-radius:var(--radius-pill);font-size:var(--text-sm);white-space:nowrap}
.bo-pill-row-draft{border-style:dashed}
.bo-limit-input{height:var(--size-36);min-height:0;width:100%;padding:var(--space-4) var(--space-8);font-size:var(--text-sm);font-family:var(--font-mono);background:var(--color-surface-field)}
.bo-status-select{height:var(--size-36);min-height:0;width:100%;padding:var(--space-4) var(--space-8);font-size:var(--text-sm)}

.bo-new-account{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--space-12);margin-top:var(--space-14);padding:var(--space-16);border:1px dashed var(--color-border-idle);border-radius:var(--radius-card)}
.bo-new-account label{gap:var(--space-4);font-size:var(--text-sm);color:var(--color-text-secondary);min-width:0}
.bo-new-account input{height:var(--size-40);min-height:0;font-size:var(--text-sm)}
.bo-new-account-actions{display:flex;align-items:flex-end;gap:var(--space-8);grid-column:1 / -1}
.bo-new-account-actions button{height:var(--size-40);min-height:0;padding-inline:var(--space-16);font-size:var(--text-sm);font-weight:var(--weight-semibold)}

.bo-people{display:flex;flex-direction:column;gap:var(--space-10);margin-top:var(--space-14)}
.bo-person{display:flex;align-items:center;gap:var(--space-10);font-size:var(--text-sm)}
body.backoffice .bo-person .avatar{width:var(--size-28);height:var(--size-28);border:1px solid var(--color-border-idle)}
.bo-person-text{display:flex;flex-direction:column;min-width:0}
.bo-person-role{color:var(--color-text-caption)}

.bo-changes{display:flex;flex-direction:column;gap:var(--space-12);margin-top:var(--space-14);font-size:var(--text-sm)}
.bo-change-when{color:var(--color-text-caption)}
.bo-change-what{margin-top:var(--space-2);overflow-wrap:anywhere}
.bo-change-why{color:var(--color-text-secondary);overflow-wrap:anywhere}

@media (max-width: 1200px){
  .bo-split{grid-template-columns:minmax(0,1fr)}
}
@media (max-width: 860px){
  .bo-fields,.bo-new-account{grid-template-columns:minmax(0,1fr)}
}

/* ===== End of ticket 18 ================================================== */

/* ===== TICKET 21 BEGIN: B2 เปิดบริษัทใหม่ (canvas frame B2, line 933) ==========
   The canvas gives this frame a 300px rail; the token scale has no 300 and tokens.css
   is generated, never hand-edited (ticket 13), so the rail takes --size-280, the width
   the operator app's settings rail already uses. Everything else is the canvas: done is
   a gold-wash check chip, current is the strong hairline in gold with a gold-filled number,
   a locked step is an idle outline carrying its reason. ===== */
.bo-b2-layout{display:grid;grid-template-columns:var(--size-280) minmax(0,1fr);gap:var(--space-28);margin-top:var(--space-24);align-items:start}
.bo-b2-rail{display:flex;flex-direction:column;gap:var(--space-8);margin:0;padding:0;list-style:none}
.bo-b2-step{display:flex;align-items:flex-start;gap:var(--space-12);min-height:var(--size-44);padding:var(--space-10) var(--space-12);border:1px solid transparent;border-radius:var(--radius-control)}
.bo-b2-step-current{border:var(--size-hairline-strong) solid var(--color-action-primary);background:var(--color-surface-selected)}
.bo-b2-step-locked{border-color:var(--color-border-idle)}
.bo-b2-mark{display:inline-flex;align-items:center;justify-content:center;width:var(--size-24);height:var(--size-24);flex:0 0 auto;border:1px solid var(--color-border-idle);border-radius:var(--radius-pill);font-size:var(--text-sm);font-weight:var(--weight-semibold);color:var(--color-text-secondary)}
.bo-b2-step-current .bo-b2-mark{border-color:transparent;background:var(--color-action-primary);color:var(--color-text-on-action)}
.bo-b2-step-done .bo-b2-mark{border-color:transparent;background:var(--color-surface-accent-chip);color:var(--color-action-primary)}
.bo-b2-step-text{display:flex;flex-direction:column;gap:var(--space-2);min-width:0}
.bo-b2-step-title{font-size:var(--text-sm);font-weight:var(--weight-semibold);color:var(--color-text-primary)}
.bo-b2-step-note{font-size:var(--text-sm);color:var(--color-text-secondary)}
.bo-b2-step-locked .bo-b2-step-title{color:var(--color-text-secondary)}

.bo-b2-main{display:flex;flex-direction:column;gap:var(--space-16);min-width:0}
.bo-b2-step-state:empty{display:none}
.bo-b2-step-state{margin-left:auto}
.bo-b2-main .bo-fields[hidden]{display:none}

/* TICKET 162: this used to carry the weight of a warning -- brick border on the problem
   wash, the same pair the console uses for a company that needs fixing -- because the
   ask it framed (`.bo-b2-ask`, `.bo-b2-units`, `.bo-b2-unit-why`, all removed with it) was
   a precondition receiving genuinely waited on. It is a plain statement now: a company
   needs no server change to receive, so the surface reads as an ordinary note, the same
   quiet treatment `.bo-note` already gives a fact worth stating and nothing more. */
.bo-b2-service{padding:var(--space-20);border:1px solid var(--color-border-default);border-radius:var(--radius-card-lg);background:var(--color-surface-card);min-width:0}
.bo-b2-service h2{margin:0 0 var(--space-8);font-size:var(--text-label);font-weight:var(--weight-semibold);line-height:var(--leading-snug)}
.bo-b2-service p{margin:0;font-size:var(--text-sm);color:var(--color-text-secondary)}

.bo-b2-opened{display:flex;flex-direction:column;align-items:flex-start;gap:var(--space-12);margin-top:var(--space-16);padding:var(--space-16) var(--space-20);border:var(--size-hairline-strong) solid var(--color-action-primary);border-radius:var(--radius-card-lg);background:var(--color-surface-selected)}
.bo-b2-opened p{margin:0;font-size:var(--text-sm);color:var(--color-text-primary)}
.bo-b2-opened-warning{font-weight:var(--weight-semibold);color:var(--color-feedback-error-text)}

/* The same fact on the company card, so the list says it too and not only this page. */
.bo-await{display:flex;flex-direction:column;gap:var(--space-2);padding:var(--space-10) var(--space-12);border:1px solid var(--color-border-danger);border-radius:var(--radius-card);background:var(--color-surface-problem-soft)}
.bo-await-title{font-size:var(--text-sm);font-weight:var(--weight-semibold);color:var(--color-feedback-error-text)}
.bo-await-note{font-size:var(--text-sm);color:var(--color-text-secondary)}

@media (max-width: 1200px){
  .bo-b2-layout{grid-template-columns:minmax(0,1fr)}
}
/* ===== TICKET 21 END ====================================================== */
/* TICKET 80: the slip-reader card's advanced fold. Tokens only; the summary is a real
   disclosure control, so it keeps the focus ring and a target size like a button. */
.bo-advanced{margin-top:var(--space-14);border:1px solid var(--color-border-default);border-radius:var(--radius-card);padding:0 var(--space-12)}
.bo-advanced>summary{cursor:pointer;min-height:var(--size-36);display:flex;align-items:center;font-size:var(--text-sm);color:var(--color-text-secondary)}
.bo-advanced>summary:focus-visible{outline:2px solid var(--color-focus-ring);outline-offset:var(--space-2)}
.bo-advanced[open]{padding-bottom:var(--space-12)}

/* ===== TICKET 162 BEGIN: Users and roles -- the company filter, the row actions and
   the four dialogs (add a person, change a role, reset a passphrase, remove from
   company). The dialog rules are app.css's own `.app-modal` family, duplicated here the
   way page-accounts-settings.css and page-system-settings.css each already carry their
   own copy rather than a shared import -- this sheet already says it defines zero custom
   properties and holds no literal colour, size, radius or duration, tokens only. ===== */
.app-modal{width:min(calc(var(--space-64)*9),100%);max-height:calc(100vh - var(--space-48));padding:0;border:1px solid var(--color-border-strong);border-radius:var(--radius-card);background:var(--color-surface-card);color:var(--color-text-primary)}
.app-modal::backdrop{background:var(--color-text-primary);opacity:var(--opacity-disabled)}
/* app.css styles every form as a wrapping row of flexible fields, which is right for the
   filter bars it was written for and wrong for a dialog stacked top to bottom. */
.app-modal-body{display:flex;flex-direction:column;align-items:stretch;gap:var(--space-16);padding:var(--space-24);margin:0}
.app-modal-body>*{flex:0 0 auto}
.app-modal-body h2{margin:0;font-size:var(--text-xl);font-weight:var(--weight-semibold)}
.app-modal-head{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--space-12)}
.app-modal-head h2{min-inline-size:0;padding-block-start:var(--space-6)}
.app-modal-close{display:inline-grid;place-items:center;flex:0 0 auto;inline-size:var(--size-44);block-size:var(--size-44);min-block-size:var(--size-44);margin:calc(var(--space-6) * -1) calc(var(--space-10) * -1) 0 0;padding:0;background:transparent;border:1px solid transparent;border-radius:var(--radius-control);color:var(--color-text-secondary)}
.app-modal-close:hover{background:var(--color-action-ghost-hover);color:var(--color-text-primary)}
.app-modal-note{margin:0;font-size:var(--text-sm);color:var(--color-text-secondary)}
.app-modal-body label{display:flex;flex:0 0 auto;flex-direction:column;gap:var(--space-6);font-size:var(--text-sm);font-weight:var(--weight-medium);color:var(--color-text-secondary)}
.app-modal-body label :is(input,select){inline-size:100%;min-inline-size:0;font-size:var(--text-md);color:var(--color-text-primary);font-weight:var(--weight-regular)}
.app-modal-actions{display:flex;align-items:center;justify-content:flex-end;gap:var(--space-12);flex-wrap:wrap;margin:var(--space-8) calc(var(--space-24) * -1) calc(var(--space-24) * -1);padding:var(--space-16) var(--space-24);background:var(--color-surface-page);border-top:1px solid var(--color-border-default);border-radius:0 0 var(--radius-card) var(--radius-card)}
/* The five roles, one line each, offered beside the role select in every dialog that
   changes one. Plain text, no card chrome: the three cards on the tab itself already
   carry that weight, and repeating it five times per dialog would outweigh the field. */
.bo-role-hints{display:flex;flex-direction:column;gap:var(--space-6);margin:calc(var(--space-8) * -1) 0 0;padding:0;list-style:none;font-size:var(--text-sm);color:var(--color-text-secondary)}
.bo-role-hints strong{color:var(--color-text-primary);font-weight:var(--weight-semibold)}

@media (max-width: 860px){
  .app-modal{width:100%;max-height:100vh;border-radius:0;border:0}
  .app-modal-body{padding:var(--space-20)}
  .app-modal-actions{flex-direction:column-reverse;align-items:stretch;margin-inline:calc(var(--space-20) * -1);padding:var(--space-16) var(--space-20)}
  .app-modal-actions button{width:100%}
}
/* ===== TICKET 162 END ====================================================== */
/* ===== TICKET 182 BEGIN: the reader cards describe the chain in use =================== */
/* A unit this install keeps off on purpose (moneyos-telegram: receiving runs inside
   moneyos-web): a hollow mark, never the grey of a unit that stopped or the red of one that
   failed, and the reason on its own line under the name. */
.bo-dot-off{background:transparent;box-shadow:inset 0 0 0 1px var(--color-border-strong)}
.bo-service{flex-wrap:wrap}
.bo-service-note{flex:1 0 100%;padding-inline-start:var(--space-18);font-size:var(--text-xs);color:var(--color-text-secondary)}
/* B1: the paired Mac's line when no slip would be read, the card's one warning. */
.bo-field-problem .bo-field-value{color:var(--color-feedback-error-text)}
/* ===== TICKET 182 END ================================================================= */
/* ===== TICKET 183 BEGIN: a failed read is said, never drawn as a draft ================= */
/* The card of a company whose reads failed: a solid lead border on the plain card, so it
   is neither the dashed draft nor the red of a problem the company has. Its pill and its
   notice are the notice family (hold text on the warning surface), the look the live
   update's offline line already gives "this figure is not current". */
.bo-card-failed{border-color:var(--color-border-lead)}
.bo-pill-failed{border-color:var(--color-border-lead);background:var(--color-feedback-warning-bg);color:var(--color-feedback-hold-text)}
.bo-load-failed{display:flex;flex-wrap:wrap;align-items:center;gap:var(--space-8) var(--space-12);padding:var(--space-10) var(--space-12);border:1px solid var(--color-border-lead);border-radius:var(--radius-card);background:var(--color-feedback-warning-bg);cursor:default}
.bo-load-failed-note{flex:1 1 var(--size-150);min-width:0;max-width:none;margin:0;font-size:var(--text-sm);color:var(--color-feedback-hold-text)}
.bo-load-failed-retry{flex:0 0 auto;display:inline-flex;align-items:center;gap:var(--space-8);min-block-size:var(--size-36);padding-block:var(--space-4);font-size:var(--text-sm)}
.bo-b1 > .bo-load-failed{margin-top:var(--space-16)}
/* A section whose read failed: the line where its figures would be, in the notice colour,
   across the whole card rather than in one column of its field grid. In the account table
   the sentence wraps at the frame's visible width (the frame is its container), not at the
   width of the columns the frame scrolls. */
.bo-failed-line{color:var(--color-feedback-hold-text)}
.bo-fields > .bo-failed-line{grid-column:1 / -1}
.bo-table-frame:has(.bo-failed-line){container-type:inline-size}
.bo-failed-text{display:block;max-inline-size:calc(100cqi - 2 * var(--space-12))}
/* ===== TICKET 183 END ================================================================= */
/* ===== TICKET 184 BEGIN: the back office on a phone ================================== */
/* --- The top bar. Above 1200px the drawer draws as its own children, so the desktop bar
       is the row it always was; its section row never wraps under the fixed-height bar (at
       1024 its second row was drawn outside the bar), and the user chip gives way instead,
       its name wrapping rather than cut. --- */
.bo-page-name,.bo-menu,.bo-scrim,.bo-drawer-head,.bo-drawer-label,.bo-logout-label{display:none}
.bo-drawer,.bo-drawer-language{display:contents}
.bo-tabs{flex-wrap:nowrap}
.bo-account{flex:0 1 auto;min-width:0}
.bo-user{min-width:0}
#bo-user-name{min-width:0;overflow-wrap:anywhere;line-height:var(--leading-snug)}
.bo-menu-close{display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;inline-size:var(--size-44);block-size:var(--size-44);min-height:0;padding:0;background:transparent;border-color:transparent;color:var(--color-text-secondary)}
.bo-menu-close:hover{background:var(--color-action-ghost-hover);border-color:transparent;color:var(--color-text-primary)}
.bo-menu-close:active{transform:none}

/* --- Every target at least 24x24 at every width (WCAG 2.5.8): the text-only controls had
       no height of their own ("ทำต่อ" measured 31x21 on production). --- */
.bo-manage,.bo-crumb-link,.bo-quiet-link{display:inline-flex;align-items:center;min-block-size:var(--size-24);min-inline-size:var(--size-24)}
.bo-crumb{align-items:center}
/* A card head's link keeps its words together ("+ Add an account" wrapped its "+" apart at 360). */
.bo-quiet-link{flex:0 0 auto;white-space:nowrap}
/* The breadcrumb's way back stays one line; a long company name wraps beside it instead. */
.bo-crumb-link{flex:0 0 auto;white-space:nowrap}
#bo-crumb-name,#bo-new-company-title{min-width:0;overflow-wrap:anywhere}

/* --- B1: one main action and the manage menu beside it; the ids and versions folded. --- */
.bo-b1-actions{display:flex;align-items:center;flex-wrap:wrap;gap:var(--space-8);margin-left:auto}
.bo-menu-wrap{position:relative;flex:0 0 auto}
.bo-b1-manage{display:inline-flex;align-items:center;gap:var(--space-6)}
.bo-b1-manage[aria-expanded=true]{background:var(--color-action-secondary-hover)}
.bo-manage-menu{position:absolute;inset-inline-end:0;inset-block-start:calc(100% + var(--space-4));z-index:var(--z-tooltip);display:flex;flex-direction:column;gap:var(--space-2);min-inline-size:max-content;max-inline-size:calc(100vw - var(--space-32));padding:var(--space-4);border:1px solid var(--color-border-default);border-radius:var(--radius-card);background:var(--color-surface-card);box-shadow:var(--shadow-sm)}
.bo-manage-menu[hidden]{display:none}
.bo-menu-item{display:flex;align-items:center;justify-content:flex-start;min-height:var(--size-44);padding-inline:var(--space-12);border:0;border-radius:var(--radius-control);background:transparent;color:var(--color-text-primary);font-size:var(--text-sm);font-weight:var(--weight-semibold);text-align:start;white-space:nowrap}
.bo-menu-item:hover{background:var(--color-action-ghost-hover);color:var(--color-text-primary)}
.bo-menu-item:active{transform:none;background:var(--color-surface-sunken)}
.bo-menu-item:focus-visible{outline-offset:calc(-1 * var(--space-2))}
/* Stopping is destructive here too: the destructive ink, and the opaque wash on hover. */
.bo-menu-item-danger{color:var(--color-action-destructive)}
.bo-menu-item-danger:hover,.bo-menu-item-danger:active{background:var(--color-action-destructive-hover);color:var(--color-action-destructive)}
.bo-b1-tech{inline-size:fit-content;max-inline-size:100%;margin-top:var(--space-12)}
.bo-b1-tech .bo-b1-meta{display:block;margin:0 0 var(--space-4)}
/* The stop confirmation at the foot of B1: the destructive look on the gate and its button. */
.bo-gate-danger{border-color:var(--color-border-danger);background:var(--color-surface-problem-soft)}
.bo-gate-danger .bo-gate-title{color:var(--color-feedback-error-text)}
.bo-gate-danger button.danger:hover{background:var(--color-surface-sunken);border-color:var(--color-action-destructive-border)}

/* --- A card's technical details (B3's queue card: what "being processed" counts). --- */
.bo-card-tech{margin-top:var(--space-14)}
.bo-card-tech-note{margin:0;font-size:var(--text-sm);line-height:var(--leading-normal);color:var(--color-text-secondary)}
.bo-read-failed{margin-top:var(--space-16)}

/* --- B4: one empty state, no detail or action box beside it; the compact width's hint. --- */
.bo-alert-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--space-12);min-block-size:calc(var(--space-64) * 4);margin:0;padding:var(--space-40) var(--space-20);text-align:center;color:var(--color-text-secondary)}
.bo-alert-empty[hidden]{display:none}
.bo-alert-empty .icon{color:var(--color-text-caption)}
.bo-alert-empty p{margin:0;font-size:var(--text-base)}
#bo-panel-alerts[data-empty=true] .bo-alert-side{display:none}
#bo-panel-alerts[data-empty=true] .bo-alert-split{grid-template-columns:minmax(0,1fr)}
.bo-alert-hint{margin:0;padding:var(--space-12) var(--space-18);border-bottom:1px solid var(--color-border-default);font-size:var(--text-sm);color:var(--color-text-secondary)}
.bo-alert-hint[hidden]{display:none}
.bo-alert-back{display:none;align-self:flex-start;align-items:center;gap:var(--space-8);min-height:var(--size-44);font-size:var(--text-sm)}
#bo-alert-detail:focus-visible{outline:2px solid var(--color-focus-ring);outline-offset:2px}
/* The chosen row's time on the problem wash: the caption grey read under AA there (axe on the
   ticket 184 harness); the secondary ink is the nearest that clears it. */
.bo-alert-row[aria-current=true] .bo-alert-time{color:var(--color-text-secondary)}

/* --- A table that is wider than its frame scrolls inside it, and says so: a shadow at the
       edge that still has columns behind it. The two covers scroll with the table and hide
       each shadow once that edge is reached, so a table that fits shows none. --- */
.bo-table-frame,body.backoffice .table-scroll{background:
  linear-gradient(to right,var(--color-surface-card),var(--color-surface-card)) left center / var(--space-16) 100% no-repeat local,
  linear-gradient(to left,var(--color-surface-card),var(--color-surface-card)) right center / var(--space-16) 100% no-repeat local,
  radial-gradient(farthest-side at 0 50%,var(--color-border-strong),transparent) left center / var(--space-10) 100% no-repeat scroll,
  radial-gradient(farthest-side at 100% 50%,var(--color-border-strong),transparent) right center / var(--space-10) 100% no-repeat scroll,
  var(--color-surface-card)}

/* --- The compact width, signed in: one row, the brand mark, the page name, the menu. --- */
@media (max-width: 1200px){
  body.backoffice:has(#workspace:not([hidden])) .bo-topbar{height:auto;min-height:var(--size-64);flex-wrap:nowrap;gap:var(--space-12);padding-block:var(--space-10)}
  body.backoffice:has(#workspace:not([hidden])) .bo-brand-text{display:none}
  body.backoffice:has(#workspace:not([hidden])) .bo-page-name{display:block;flex:1 1 auto;min-width:0;max-width:none;margin:0;font-size:var(--text-md);font-weight:var(--weight-semibold);line-height:var(--leading-snug);color:var(--color-text-primary);overflow-wrap:anywhere}
  body.backoffice:has(#workspace:not([hidden])) .bo-menu{display:inline-flex;align-items:center;gap:var(--space-8);flex:0 0 auto;min-height:var(--size-44);min-width:var(--size-44);padding-inline:var(--space-12);background:var(--color-action-secondary-bg);border-color:var(--color-action-secondary-border);color:var(--color-action-secondary-text);font-size:var(--text-sm)}
  body.backoffice:has(#workspace:not([hidden])) .bo-menu:hover{background:var(--color-action-secondary-hover)}
  body.backoffice:has(#workspace:not([hidden])) .bo-menu:active{background:var(--color-surface-sunken)}
  body.backoffice:has(#workspace:not([hidden])) .bo-drawer{display:none}

  /* Open: a panel over the page's end edge, the scrim behind it (backoffice.js owns open,
     close, the focus trap and Escape). */
  body.backoffice[data-bo-drawer=open]{overflow:hidden}
  body.backoffice[data-bo-drawer=open]:has(#workspace:not([hidden])) .bo-scrim{display:block;position:fixed;inset:0;z-index:var(--z-overlay);background:var(--color-text-primary);opacity:var(--opacity-disabled)}
  body.backoffice[data-bo-drawer=open]:has(#workspace:not([hidden])) .bo-drawer{display:flex;flex-direction:column;position:fixed;inset-block:0;inset-inline-end:0;z-index:var(--z-modal);inline-size:min(calc(var(--space-64) * 5),calc(100% - var(--space-48)));gap:var(--space-16);padding:var(--space-12) var(--space-16) var(--space-24);overflow-y:auto;overscroll-behavior:contain;background:var(--color-surface-card);border-inline-start:1px solid var(--color-border-default);box-shadow:var(--shadow-sm)}
  body.backoffice:has(#workspace:not([hidden])) .bo-drawer-head{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--space-12);padding-block-end:var(--space-12);border-block-end:1px solid var(--color-border-default)}
  .bo-drawer-titles{display:flex;flex-direction:column;gap:var(--space-2);min-width:0;padding-block-start:var(--space-4)}
  .bo-drawer-title{font-size:var(--text-md);font-weight:var(--weight-semibold);color:var(--color-text-primary)}
  .bo-drawer-current{font-size:var(--text-sm);color:var(--color-text-secondary);overflow-wrap:anywhere}
  body.backoffice:has(#workspace:not([hidden])) .bo-console{display:block;flex:0 0 auto}
  body.backoffice:has(#workspace:not([hidden])) .bo-tabs{flex-direction:column;align-items:stretch;gap:var(--space-4)}
  body.backoffice:has(#workspace:not([hidden])) .bo-tabs button{height:auto;min-height:var(--size-48);justify-content:flex-start;padding-inline:var(--space-12);border-bottom:0;border-inline-start:var(--size-marker) solid transparent;border-radius:var(--radius-control);font-size:var(--text-base);white-space:normal;text-align:start}
  body.backoffice:has(#workspace:not([hidden])) .bo-tabs button[aria-current=page]{background:var(--color-surface-selected);border-inline-start-color:var(--color-action-primary);color:var(--color-text-primary)}
  body.backoffice:has(#workspace:not([hidden])) .bo-tabs button[aria-current=page]:hover{background:var(--color-surface-accent-chip)}
  body.backoffice:has(#workspace:not([hidden])) .bo-tabs .bo-tab-badge{margin-inline-start:auto}
  body.backoffice:has(#workspace:not([hidden])) .bo-drawer-language{display:flex;align-items:center;justify-content:space-between;gap:var(--space-12);padding-block-start:var(--space-16);border-block-start:1px solid var(--color-border-default)}
  body.backoffice:has(#workspace:not([hidden])) .bo-drawer-label{display:block;font-size:var(--text-sm);color:var(--color-text-secondary)}
  body.backoffice:has(#workspace:not([hidden])) .language-switch{margin-left:0}
  body.backoffice:has(#workspace:not([hidden])) .language-switch button{height:var(--size-44)}
  body.backoffice:has(#workspace:not([hidden])) .bo-account{flex:0 0 auto;flex-direction:column;align-items:stretch;gap:var(--space-12);margin-top:auto;padding-block-start:var(--space-16);border-block-start:1px solid var(--color-border-default)}
  body.backoffice:has(#workspace:not([hidden])) #bo-logout{inline-size:100%;block-size:var(--size-44);gap:var(--space-8);font-size:var(--text-sm);font-weight:var(--weight-semibold)}
  body.backoffice:has(#workspace:not([hidden])) .bo-logout-label{display:inline}

  /* B4 at this width is one column: the list, or the one alert chosen, never both. */
  #bo-panel-alerts[data-view=list] .bo-alert-side{display:none}
  #bo-panel-alerts[data-view=detail] .bo-alert-card,#bo-panel-alerts[data-view=detail] #bo-alert-filters{display:none}
  #bo-panel-alerts[data-view=detail] .bo-alert-back{display:inline-flex}
}

/* --- A phone: the 16px gutter, the four overview figures as a 2x2 grid of compact tiles
       so the company list starts in the first screen, and primary actions on --size-44. --- */
@media (max-width: 860px){
  body.backoffice main{padding:var(--space-20) var(--space-16) var(--space-40)}
  body.backoffice:has(#workspace:not([hidden])) .bo-topbar{padding-inline:var(--space-16)}
  .bo-page-head{gap:var(--space-12)}
  .bo-page-head > .bo-primary{flex:1 1 100%;justify-content:center}
  .bo-tiles{grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--space-8);margin-top:var(--space-16)}
  .bo-tile{gap:var(--space-4);padding:var(--space-12) var(--space-14);border-radius:var(--radius-card)}
  .bo-tile-value{font-size:var(--text-xl)}
  .bo-tiles > .bo-tile:last-child:nth-child(odd){grid-column:1 / -1}
  .bo-cards{gap:var(--space-12);margin-top:var(--space-12)}
  .bo-card{padding:var(--space-16);gap:var(--space-12)}
  .bo-manage,.bo-crumb-link,.bo-quiet-link{min-block-size:var(--size-44);min-inline-size:var(--size-44);justify-content:center}
  .bo-b1-head{gap:var(--space-10)}
  .bo-b1-actions{flex:1 1 100%;margin-left:0}
  .bo-b1-actions > .bo-b1-action{flex:1 1 auto}
  .bo-b1-action{height:var(--size-44);min-height:var(--size-44)}
  .bo-action-row a,.bo-action-row button{height:var(--size-44);min-height:var(--size-44)}
  /* The controls a phone page is used through: the filters, the audit download, a failed
     read's retry (ticket 183's quiet 36 stays on the desktop) and the folded details. */
  .bo-chips button,body.backoffice .bo-filter select,#bo-audit-csv,.bo-load-failed-retry,.bo-advanced>summary{min-height:var(--size-44)}
  .bo-chips button,body.backoffice .bo-filter select,#bo-audit-csv{height:var(--size-44)}
  /* B1's accounts: each account a stack of label and value, so its limit and today's use are
     on screen without scrolling the table sideways. The column names are the cells' own
     data-label (backoffice.js); the header row stays for a screen reader. */
  #bo-b1-accounts,#bo-b1-accounts tbody,#bo-b1-accounts tr,#bo-b1-accounts td{display:block}
  .bo-table-frame:has(#bo-b1-accounts){position:relative}
  #bo-b1-accounts thead{position:absolute;inline-size:1px;block-size:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;margin:-1px}
  #bo-b1-accounts tbody tr{padding:var(--space-8) var(--space-12)}
  #bo-b1-accounts tbody tr:first-child{border-top:0}
  #bo-b1-accounts td{display:flex;align-items:center;justify-content:space-between;gap:var(--space-12);min-width:0;padding:var(--space-6) 0;text-align:end}
  #bo-b1-accounts td:not([data-label]){display:block;text-align:start}
  #bo-b1-accounts td[data-label]::before{content:attr(data-label);flex:0 0 auto;font-family:var(--font-sans);color:var(--color-text-caption);text-align:start}
  #bo-b1-accounts td > :is(input,select){flex:0 1 var(--size-150);inline-size:auto;min-inline-size:0}
}
/* ===== TICKET 184 END =============================================================== */
/* ===== TICKET 196 BEGIN: one person, many companies, in Users and roles =================
   The list (search, a company filter that takes several, a role filter, by person or by
   company), one person's page (their companies and roles, the add-companies picker, the
   review before saving and each company's result) and the two new dialogs. Tokens only;
   the destructive controls wear the danger variant with the opaque hover the console's
   other destructive controls use (`.bo-b1-action.danger:hover`). ========================= */
.bo-users-head-actions{display:flex;flex-wrap:wrap;align-items:center;gap:var(--space-8);margin-left:auto}
.bo-users-done:empty{display:none}
.bo-users-done{margin:var(--space-16) 0 0;padding:var(--space-12) var(--space-16);border:1px solid var(--color-border-default);border-radius:var(--radius-card);background:var(--color-feedback-success-bg);color:var(--color-feedback-success-text);font-size:var(--text-sm);max-width:none}
#bo-users-partial:empty{display:none}
#bo-users-partial{margin-top:var(--space-16)}
.bo-users-hint{margin:0;font-size:var(--text-sm);line-height:var(--leading-normal);color:var(--color-text-secondary)}

/* --- The list's tools. --- */
.bo-users-tools{display:flex;flex-wrap:wrap;align-items:flex-start;gap:var(--space-8);margin-top:var(--space-20)}
.bo-users-search{flex:1 1 var(--size-280);margin-left:0;height:var(--size-40)}
.bo-users-pop{position:relative;flex:0 0 auto}
.bo-users-pop-button{display:inline-flex;align-items:center;gap:var(--space-10);height:var(--size-40);padding-inline:var(--space-14);border:1px solid var(--color-border-strong);border-radius:var(--radius-control);background:transparent;color:var(--color-text-primary);font-size:var(--text-sm);white-space:nowrap;cursor:pointer;list-style:none}
.bo-users-pop-button::-webkit-details-marker{display:none}
.bo-users-pop-button::after{content:'';inline-size:var(--space-6);block-size:var(--space-6);margin-block-start:calc(var(--space-4) * -1);border-inline-end:var(--size-hairline-strong) solid currentColor;border-block-end:var(--size-hairline-strong) solid currentColor;transform:rotate(45deg)}
.bo-users-pop[open] > .bo-users-pop-button::after{margin-block-start:var(--space-4);transform:rotate(225deg)}
.bo-users-pop-button:hover{background:var(--color-action-ghost-hover)}
.bo-users-pop-body{position:absolute;z-index:var(--z-tooltip);inset-block-start:calc(100% + var(--space-4));inset-inline-start:0;display:flex;flex-direction:column;gap:var(--space-8);min-inline-size:var(--size-280);max-inline-size:calc(100vw - var(--space-32));margin:0;padding:var(--space-12);border:1px solid var(--color-border-default);border-radius:var(--radius-card);background:var(--color-surface-card);box-shadow:var(--shadow-sm)}
.bo-users-checks{display:flex;flex-direction:column;gap:var(--space-2)}
/* app.css gives every label a column and a flexible basis meant for a form; a checkbox sits
   beside its own words, and the box keeps its size instead of stretching to the row. */
body.backoffice .bo-users-check,body.backoffice .bo-users-pick{display:flex;flex:0 0 auto;flex-direction:row;align-items:center;gap:var(--space-10);min-height:var(--size-44);padding:var(--space-4) var(--space-8);border-radius:var(--radius-control);font-size:var(--text-sm);font-weight:var(--weight-regular);color:var(--color-text-primary);cursor:pointer}
.bo-users-check:hover,.bo-users-pick:hover{background:var(--color-action-ghost-hover)}
body.backoffice .bo-users-check input,body.backoffice .bo-users-pick input{flex:0 0 auto;inline-size:var(--size-24);block-size:var(--size-24);min-height:0;min-inline-size:0;margin:0;padding:0;accent-color:var(--color-action-primary)}
.bo-users-views{display:inline-flex;gap:var(--space-4)}
.bo-users-views .bo-chip{height:var(--size-40);min-height:var(--size-40)}
.bo-users-result-head{display:flex;align-items:baseline;flex-wrap:wrap;gap:var(--space-8) var(--space-12);margin-top:var(--space-16)}
.bo-users-count{margin:0;max-width:none;font-size:var(--text-sm);color:var(--color-text-secondary)}
.bo-users-result-head .bo-quiet-link{margin-left:auto}

/* --- By person: one row per account, each company beside its own role. --- */
body.backoffice .bo-users-table td{vertical-align:top}
.bo-users-name{font-weight:var(--weight-semibold);overflow-wrap:anywhere}
.bo-users-you{display:inline-flex;align-items:center;height:var(--size-24);padding-inline:var(--space-8);border-radius:var(--radius-pill);background:var(--color-surface-accent-chip);color:var(--color-action-primary);font-size:var(--text-xs);font-weight:var(--weight-semibold)}
.bo-users-pairs{display:flex;flex-wrap:wrap;gap:var(--space-6) var(--space-8);margin:0;padding:0;list-style:none}
.bo-users-pair{display:inline-flex;align-items:center;flex-wrap:wrap;gap:var(--space-4) var(--space-6);min-width:0;max-width:100%;padding:var(--space-2) var(--space-2) var(--space-2) var(--space-10);border:1px solid var(--color-border-default);border-radius:var(--radius-pill);background:var(--color-surface-card)}
.bo-users-pair:has(> .bo-role-pill-system){padding-inline-start:var(--space-2);padding-inline-end:var(--space-10)}
.bo-users-pair-company{font-size:var(--text-sm);font-weight:var(--weight-medium);color:var(--color-text-primary);overflow-wrap:anywhere}
.bo-users-pair-sep{color:var(--color-text-caption)}
.bo-users-pair .bo-role-pill-system{margin-inline-end:0}
.bo-users-more{align-self:center;font-size:var(--text-sm);color:var(--color-text-secondary)}
.bo-users-open{height:var(--size-36);min-height:var(--size-36);padding-inline:var(--space-14);font-size:var(--text-sm)}
.bo-users-role-cell{display:flex;flex-wrap:wrap;gap:var(--space-6)}
body.backoffice td.bo-users-role-cell{display:table-cell}

/* --- By company: each company's own members, its read failing on its own. --- */
.bo-users-company-view{display:flex;flex-direction:column;gap:var(--space-16);margin-top:var(--space-16)}
.bo-users-company{padding:var(--space-16) var(--space-20);border:1px solid var(--color-border-default);border-radius:var(--radius-card-lg);background:var(--color-surface-card);min-width:0}
.bo-users-company-head{display:flex;align-items:baseline;flex-wrap:wrap;gap:var(--space-4) var(--space-10)}
.bo-users-company-head h2{margin:0;font-size:var(--text-label);line-height:var(--leading-snug);overflow-wrap:anywhere}
.bo-users-company > .bo-users-hint,.bo-users-company > .bo-load-failed{margin-top:var(--space-12)}
body.backoffice .bo-users-company .table-scroll{margin-top:var(--space-12)}
/* Every company's table lines its columns up with the next one's: fixed widths, not the
   widths each table's own content would pick. */
body.backoffice .bo-users-company .bo-users-table{table-layout:fixed}
.bo-users-company .bo-users-table th:first-child{inline-size:45%}
.bo-users-company .bo-users-table th:last-child{inline-size:20%}
.bo-users-empty{margin:var(--space-16) 0 0;max-width:none;padding:var(--space-32) var(--space-20);border:1px dashed var(--color-border-idle);border-radius:var(--radius-card-lg);text-align:center;font-size:var(--text-sm);color:var(--color-text-secondary)}
.bo-users-help{margin-top:var(--space-16)}
.bo-users-help[open]{display:flex;flex-direction:column;gap:var(--space-10)}
.bo-users-help .bo-role-hints{margin:0}

/* --- One person's page. --- */
.bo-users-manage-head{display:flex;align-items:center;gap:var(--space-14);margin-top:var(--space-10)}
body.backoffice .bo-users-manage-head .avatar{flex:0 0 auto;inline-size:var(--size-48);block-size:var(--size-48);border:1px solid var(--color-border-idle);font-size:var(--text-md)}
.bo-users-manage-titles{min-width:0}
.bo-users-manage-titles h1{font-size:var(--text-xxl);font-weight:var(--weight-semibold);letter-spacing:-0.02em;line-height:var(--leading-tight);overflow-wrap:anywhere}
.bo-users-manage-titles h1:focus-visible{outline:2px solid var(--color-focus-ring);outline-offset:2px;border-radius:var(--radius-sm)}
.bo-users-sub{margin:var(--space-4) 0 0;max-width:none;font-size:var(--text-sm);color:var(--color-text-secondary)}
.bo-users-moved{margin-top:var(--space-16)}
.bo-users-manage-grid{display:grid;grid-template-columns:minmax(0,3fr) minmax(0,2fr);gap:var(--space-16);margin-top:var(--space-16);align-items:start}
.bo-users-card-head{align-items:center;justify-content:space-between;flex-wrap:wrap}
.bo-users-small{height:var(--size-36);min-height:var(--size-36);padding-inline:var(--space-12);border-radius:var(--radius-control);font-size:var(--text-sm);font-weight:var(--weight-semibold)}
.bo-users-small.danger:hover,.bo-users-save.danger:hover{background:var(--color-surface-sunken);border-color:var(--color-action-destructive-border)}
.bo-users-system{display:flex;flex-wrap:wrap;align-items:center;gap:var(--space-8);margin:var(--space-14) 0 0;max-width:none}
.bo-users-access{margin:var(--space-14) 0 0;padding:0;list-style:none;border:1px solid var(--color-border-default);border-radius:var(--radius-card);overflow:hidden}
.bo-users-row{display:grid;grid-template-columns:minmax(0,2fr) minmax(0,3fr);gap:var(--space-8) var(--space-16);align-items:start;padding:var(--space-14) var(--space-16);border-top:1px solid var(--color-border-default)}
.bo-users-row:first-child{border-top:0}
.bo-users-row-add{background:var(--color-surface-selected)}
.bo-users-row-withdraw{background:var(--color-surface-problem-soft)}
.bo-users-row-name{display:flex;flex-wrap:wrap;align-items:center;gap:var(--space-6) var(--space-8);min-width:0;padding-block-start:var(--space-8)}
.bo-users-row-name strong{font-size:var(--text-base);overflow-wrap:anywhere}
.bo-users-row-body{display:flex;flex-direction:column;align-items:flex-start;gap:var(--space-8);min-width:0}
.bo-users-row-empty{padding:var(--space-16)}
body.backoffice .bo-users-role-field{flex:0 0 auto;inline-size:100%}
body.backoffice .bo-users-role-field select{height:var(--size-40);min-height:var(--size-40);font-size:var(--text-sm)}
body.backoffice .bo-users-role-field select[aria-invalid=true]{border-color:var(--color-border-lead)}
.bo-users-hint-needed{color:var(--color-feedback-hold-text)}
.bo-users-tag{display:inline-flex;align-items:center;height:var(--size-24);padding-inline:var(--space-8);border-radius:var(--radius-pill);background:var(--color-surface-accent-chip);color:var(--color-action-primary);font-size:var(--text-xs);font-weight:var(--weight-semibold);white-space:nowrap}
.bo-users-tag-danger{background:var(--color-feedback-error-bg);color:var(--color-feedback-error-text)}

/* The picker: the companies where this session manages users, searchable, several at once;
   one already held is marked and cannot be ticked again. */
.bo-users-picker{display:flex;flex-direction:column;gap:var(--space-10);margin-top:var(--space-14);padding:var(--space-16);border:var(--size-hairline-strong) solid var(--color-action-primary);border-radius:var(--radius-card);background:var(--color-surface-card)}
.bo-users-picker-head{display:flex;align-items:baseline;justify-content:space-between;flex-wrap:wrap;gap:var(--space-4) var(--space-12)}
.bo-users-picker-head h3{margin:0;font-size:var(--text-md)}
.bo-users-picker-search{margin-left:0;min-width:0;inline-size:100%}
.bo-users-picker-list{display:flex;flex-direction:column;gap:var(--space-2);max-block-size:calc(var(--space-64) * 5);margin:0;padding:0;overflow-y:auto;list-style:none}
body.backoffice .bo-users-pick{flex-wrap:wrap;row-gap:var(--space-2)}
.bo-users-pick:has(input:checked:not(:disabled)){background:var(--color-surface-selected)}
.bo-users-pick:has(input:disabled){cursor:not-allowed}
.bo-users-pick:has(input:disabled):hover{background:transparent}
.bo-users-pick-text{display:flex;flex:1 1 var(--size-150);flex-direction:column;min-width:0}
.bo-users-pick-name{font-weight:var(--weight-semibold);overflow-wrap:anywhere}
.bo-users-pick-id{font-size:var(--text-xs);color:var(--color-text-secondary)}
.bo-users-pick-state{flex:1 1 100%;padding-inline-start:calc(var(--size-24) + var(--space-10));font-size:var(--text-xs);color:var(--color-text-secondary)}
.bo-users-picker-foot{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:var(--space-8) var(--space-12)}
.bo-users-picker-foot .bo-users-hint{flex:1 1 var(--size-150)}
.bo-users-passphrase:empty{display:none}
.bo-users-passphrase{margin-top:var(--space-14);padding-top:var(--space-14);border-top:1px solid var(--color-border-default)}

/* The review: what changes, one reason, one save that names the count, each company's result. */
.bo-users-review{position:sticky;top:var(--space-16)}
.bo-users-review h2{margin:0}
body.backoffice table.bo-users-review-table{min-width:0;margin-top:var(--space-12);border:1px solid var(--color-border-default);border-radius:var(--radius-card);border-collapse:separate;border-spacing:0;overflow:hidden}
body.backoffice .bo-users-review-table th,body.backoffice .bo-users-review-table td{padding:var(--space-8) var(--space-10);vertical-align:top;overflow-wrap:anywhere}
#bo-users-review > .bo-users-hint{margin-top:var(--space-12)}
#bo-users-review-same:empty,#bo-users-missing:empty{display:none}
#bo-users-review-same,#bo-users-missing{margin-top:var(--space-10);max-width:none}
#bo-users-missing{color:var(--color-feedback-hold-text)}
.bo-users-needed{color:var(--color-feedback-hold-text)}
.bo-users-danger-text{color:var(--color-feedback-error-text)}
.bo-users-warning{margin:var(--space-12) 0 0;max-width:none;padding:var(--space-10) var(--space-12);border:1px solid var(--color-border-danger);border-radius:var(--radius-card);background:var(--color-surface-problem-soft);color:var(--color-feedback-error-text);font-size:var(--text-sm);font-weight:var(--weight-semibold)}
body.backoffice .bo-users-reason{display:flex;flex:0 0 auto;flex-direction:column;gap:var(--space-6);margin-top:var(--space-16);font-size:var(--text-sm);font-weight:var(--weight-medium);color:var(--color-text-secondary)}
body.backoffice .bo-users-reason textarea{min-height:var(--size-72);font-size:var(--text-sm);color:var(--color-text-primary)}
.bo-users-reason + .bo-users-hint{margin-top:var(--space-6)}
.bo-users-save{inline-size:100%;min-height:var(--size-48);margin-top:var(--space-14);padding-inline:var(--space-18);border-radius:var(--radius-control);font-size:var(--text-sm);font-weight:var(--weight-semibold);white-space:normal}
.bo-users-save:disabled{background:var(--color-action-disabled-bg);border-color:var(--color-action-disabled-border);color:var(--color-action-disabled-text);opacity:1;cursor:not-allowed}
.bo-users-status:empty{display:none}
.bo-users-status{margin:var(--space-12) 0 0;max-width:none;font-size:var(--text-sm);font-weight:var(--weight-semibold);color:var(--color-text-primary)}
.bo-users-status:focus-visible{outline:2px solid var(--color-focus-ring);outline-offset:2px;border-radius:var(--radius-sm)}
.bo-users-results:empty{display:none}
.bo-users-results{display:flex;flex-direction:column;gap:var(--space-8);margin-top:var(--space-12)}
.bo-users-results-title{margin:0;font-size:var(--text-md)}
.bo-users-result-list{display:flex;flex-direction:column;gap:var(--space-8);margin:0;padding:0;list-style:none}
.bo-users-result{display:flex;flex-direction:column;align-items:flex-start;gap:var(--space-4);padding:var(--space-10) var(--space-12);border:1px solid var(--color-border-default);border-radius:var(--radius-card);font-size:var(--text-sm);color:var(--color-text-secondary)}
.bo-users-result strong{color:var(--color-text-primary);overflow-wrap:anywhere}
.bo-users-result-done,.bo-users-result-already{background:var(--color-feedback-success-bg);color:var(--color-feedback-success-text)}
.bo-users-result-refused,.bo-users-result-unapplied{border-color:var(--color-border-danger);background:var(--color-surface-problem-soft);color:var(--color-feedback-error-text)}
.bo-users-result-conflict,.bo-users-result-unknown{border-color:var(--color-border-lead);background:var(--color-feedback-warning-bg);color:var(--color-feedback-hold-text)}
.bo-users-results > .bo-users-hint{max-width:none}
.bo-users-error{color:var(--color-feedback-error-text)}

@media (max-width: 1200px){
  .bo-users-manage-grid{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}
}
/* A phone: every control on --size-44, the filters one to a row, and each list row, access
   row and review row a readable stack instead of a table that scrolls the page sideways. */
@media (max-width: 860px){
  .bo-users-head-actions{flex:1 1 100%;margin-left:0}
  .bo-users-head-actions > .bo-primary{flex:1 1 100%;justify-content:center}
  .bo-users-tools{gap:var(--space-8)}
  .bo-users-search{flex:1 1 100%;min-width:0;height:var(--size-44)}
  .bo-users-pop{flex:1 1 100%}
  .bo-users-pop-button{inline-size:100%;justify-content:space-between;height:var(--size-44);white-space:normal}
  .bo-users-pop-body{position:static;min-inline-size:0;max-inline-size:none;margin-top:var(--space-6);box-shadow:none}
  .bo-users-tools .bo-filter{flex:1 1 100%}
  body.backoffice .bo-users-tools .bo-filter select{inline-size:100%}
  .bo-users-views{flex:1 1 100%}
  .bo-users-views .bo-chip{flex:1 1 0;height:var(--size-44);min-height:var(--size-44)}
  body.backoffice table.bo-users-table,body.backoffice .bo-users-company .bo-users-table{min-width:0;table-layout:auto}
  .bo-users-table,.bo-users-table tbody,.bo-users-table tr,body.backoffice .bo-users-table td{display:block}
  .bo-users-table thead{position:absolute;inline-size:1px;block-size:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;margin:-1px}
  .bo-users-table tbody tr{display:flex;flex-direction:column;gap:var(--space-8);padding:var(--space-12) var(--space-14);border-top:1px solid var(--color-border-default)}
  .bo-users-table tbody tr:first-child{border-top:0}
  body.backoffice .bo-users-table td{padding:0;border-bottom:0}
  body.backoffice .bo-users-table .bo-edit-cell{text-align:start}
  .bo-users-open{inline-size:100%;height:var(--size-44);min-height:var(--size-44)}
  .bo-users-company{padding:var(--space-14)}
  .bo-users-manage-grid{grid-template-columns:minmax(0,1fr)}
  .bo-users-review{position:static}
  .bo-users-row{grid-template-columns:minmax(0,1fr);padding:var(--space-12) var(--space-14)}
  .bo-users-row-name{padding-block-start:0}
  .bo-users-small{height:var(--size-44);min-height:var(--size-44)}
  .bo-users-row-body .bo-users-small{inline-size:100%}
  body.backoffice .bo-users-role-field select{height:var(--size-44);min-height:var(--size-44)}
  .bo-users-review-table thead{position:absolute;inline-size:1px;block-size:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;margin:-1px}
  .bo-users-review-table,.bo-users-review-table tbody,.bo-users-review-table tr{display:block}
  .bo-users-review-table tbody tr{padding:var(--space-8) var(--space-10);border-top:1px solid var(--color-border-default)}
  .bo-users-review-table tbody tr:first-child{border-top:0}
  body.backoffice .bo-users-review-table td{display:flex;justify-content:space-between;gap:var(--space-12);padding:var(--space-4) 0;border-bottom:0;text-align:end}
  body.backoffice .bo-users-review-table td::before{content:attr(data-label);flex:0 0 auto;color:var(--color-text-caption);text-align:start}
}
/* ===== TICKET 196 END =============================================================== */
/* ===== TICKET 231 BEGIN: SMS ธนาคาร, the phones that forward bank SMS ===================
   The section's lead, the phone cards, the three tables, the pairing help and the three
   dialogs. Tokens only, like the rest of this sheet. What leads is the lead band: an OTP let
   through or a phone with no key in the destructive look, a silent phone in the hold look,
   the empty stage and the all-heard state quiet. Destructive controls wear the danger
   variant in the trigger and in the confirm (`.danger-fill`, the operator app's confirm
   button), hovering onto an opaque fill as the console's other destructive controls do. === */
.bo-sms-refresh{height:var(--size-40);min-height:var(--size-40);padding-inline:var(--space-16);font-size:var(--text-sm);font-weight:var(--weight-semibold)}
.bo-sms-intro{margin:var(--space-12) 0 0;max-width:78ch;font-size:var(--text-sm);line-height:var(--leading-normal);color:var(--color-text-secondary)}
.bo-sms-denied{margin:var(--space-20) 0 0;max-width:none;padding:var(--space-16) var(--space-20);border:1px solid var(--color-border-lead);border-radius:var(--radius-card);background:var(--color-surface-lead);color:var(--color-feedback-hold-text);font-size:var(--text-base)}
.bo-sms-failed{margin-top:var(--space-16)}
.bo-sms-failed-copy{display:flex;flex:1 1 var(--size-280);flex-direction:column;gap:var(--space-4);min-width:0}
/* The console's note is a row item with a basis (ticket 183); in this column it would be a height. */
.bo-sms-failed-copy .bo-load-failed-note{flex:0 0 auto}
.bo-sms-done:empty{display:none}
.bo-sms-done{margin:var(--space-16) 0 0;max-width:none;padding:var(--space-12) var(--space-16);border:1px solid var(--color-border-default);border-radius:var(--radius-card);background:var(--color-feedback-success-bg);color:var(--color-feedback-success-text);font-size:var(--text-sm);font-weight:var(--weight-semibold)}
.bo-sms-done:focus-visible{outline:2px solid var(--color-focus-ring);outline-offset:2px}

/* --- The lead: one band, the first place the eye lands. --- */
.bo-sms-lead{display:flex;align-items:flex-start;gap:var(--space-16);margin-top:var(--space-20);padding:var(--space-20) var(--space-24);border:1px solid var(--color-border-default);border-radius:var(--radius-card-lg);background:var(--color-surface-card)}
.bo-sms-lead-icon{display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;inline-size:var(--size-44);block-size:var(--size-44);border-radius:var(--radius-pill);background:var(--color-surface-sunken);color:var(--color-text-secondary)}
.bo-sms-lead-icon .icon{inline-size:var(--space-24);block-size:var(--space-24)}
.bo-sms-lead-copy{display:flex;flex-direction:column;align-items:flex-start;gap:var(--space-8);min-width:0}
.bo-sms-lead-title{margin:0;max-width:none;font-size:var(--text-xl);font-weight:var(--weight-semibold);line-height:var(--leading-snug);color:var(--color-text-primary);overflow-wrap:anywhere}
.bo-sms-lead-body{margin:0;max-width:78ch;font-size:var(--text-base);line-height:var(--leading-normal);color:var(--color-text-primary)}
.bo-sms-lead-more{margin:0;font-size:var(--text-sm);color:var(--color-text-secondary)}
.bo-sms-lead-link{display:inline-flex;align-items:center;min-block-size:var(--size-24);font-size:var(--text-sm);font-weight:var(--weight-semibold);color:var(--color-text-link)}
.bo-sms-lead-link:hover{text-decoration:none}
.bo-sms-lead-link:active{color:var(--color-action-primary-hover)}
.bo-sms-lead-danger{border-color:var(--color-border-danger);background:var(--color-surface-problem-soft)}
.bo-sms-lead-danger .bo-sms-lead-icon{background:var(--color-surface-problem);color:var(--color-feedback-error-text)}
.bo-sms-lead-danger .bo-sms-lead-title{color:var(--color-feedback-error-text)}
.bo-sms-lead-warning{border-color:var(--color-border-lead);background:var(--color-surface-lead)}
.bo-sms-lead-warning .bo-sms-lead-icon{background:var(--color-feedback-warning-bg);color:var(--color-feedback-hold-text)}
.bo-sms-lead-warning .bo-sms-lead-title{color:var(--color-feedback-hold-text)}
.bo-sms-lead-ok{background:var(--color-surface-accent-soft)}
.bo-sms-lead-ok .bo-sms-lead-icon{background:var(--color-surface-accent-chip);color:var(--color-action-primary)}
.bo-sms-lead-empty{padding-block:var(--space-28)}

/* --- Sections. --- */
.bo-sms-section{margin-top:var(--space-24)}
.bo-sms-card{margin-top:var(--space-16)}
.bo-sms-section-head{display:flex;align-items:center;flex-wrap:wrap;gap:var(--space-8) var(--space-12)}
.bo-sms-section-head h2{margin:0;font-size:var(--text-label);font-weight:var(--weight-semibold);line-height:var(--leading-snug)}
.bo-sms-section-head > button{margin-left:auto}
.bo-sms-card-note{margin:var(--space-14) 0 0;max-width:none;font-size:var(--text-sm);line-height:var(--leading-normal);color:var(--color-text-secondary)}
.bo-sms-split{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--space-16);align-items:start}
.bo-sms-split > .bo-sms-card{margin-top:var(--space-16)}
.bo-sms-small{display:inline-flex;align-items:center;justify-content:center;gap:var(--space-6);height:var(--size-36);min-height:var(--size-36);padding-inline:var(--space-12);border-radius:var(--radius-control);font-size:var(--text-sm);font-weight:var(--weight-semibold)}
.bo-sms-small:active{transform:none;background:var(--color-surface-sunken)}
.bo-sms-small.danger:hover{background:var(--color-surface-sunken);border-color:var(--color-action-destructive-border)}
.bo-sms-small:disabled{background:var(--color-action-disabled-bg);border-color:var(--color-action-disabled-border);color:var(--color-action-disabled-text);opacity:1;cursor:not-allowed}
.bo-sms-mono{font-family:var(--font-mono);overflow-wrap:anywhere}
.bo-sms-caption{margin:0;max-width:none;font-size:var(--text-sm);line-height:var(--leading-normal);color:var(--color-text-caption)}
.bo-sms-empty{margin:var(--space-14) 0 0;max-width:none;padding:var(--space-20);border:1px dashed var(--color-border-idle);border-radius:var(--radius-card);font-size:var(--text-sm);line-height:var(--leading-normal);color:var(--color-text-secondary)}
.bo-sms-empty p{margin:0;max-width:none;font-size:var(--text-sm);color:var(--color-text-secondary)}
.bo-sms-empty .bo-sms-empty-title{margin-bottom:var(--space-6);font-size:var(--text-base);font-weight:var(--weight-semibold);color:var(--color-text-primary)}
.bo-sms-unread{margin:var(--space-14) 0 0;max-width:none;padding:var(--space-10) var(--space-12);border:1px solid var(--color-border-lead);border-radius:var(--radius-card);background:var(--color-feedback-warning-bg);color:var(--color-feedback-hold-text);font-size:var(--text-sm)}

/* --- Phones: one card each. The silent one carries the hold marker down its edge. --- */
.bo-sms-phones{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(100%,calc(var(--size-280) + var(--space-64))),1fr));gap:var(--space-16);margin:var(--space-14) 0 0;padding:0;list-style:none}
.bo-sms-phone{display:flex;flex-direction:column;gap:var(--space-14);min-width:0;padding:var(--space-20);border:1px solid var(--color-border-default);border-radius:var(--radius-card-lg);background:var(--color-surface-card)}
.bo-sms-phone-problem{border-color:var(--color-border-danger);border-inline-start:var(--size-marker) solid var(--color-action-destructive)}
/* After the problem rule on purpose: a silent phone is drawn silent whatever else it has, as the
   lead names it; its red warnings say the rest inside the card. */
.bo-sms-phone-silent{border-color:var(--color-border-lead);border-inline-start:var(--size-marker) solid var(--color-feedback-hold-text);background:var(--color-surface-lead)}
.bo-sms-phone-revoked{border-style:dashed;border-color:var(--color-border-idle);background:var(--color-surface-draft)}
.bo-sms-phone-head{display:flex;align-items:flex-start;flex-wrap:wrap;gap:var(--space-8) var(--space-10)}
.bo-sms-phone-name{display:flex;flex:1 1 var(--size-150);flex-direction:column;gap:var(--space-2);min-width:0}
.bo-sms-phone-name h3{margin:0;font-size:var(--text-label);font-weight:var(--weight-semibold);line-height:var(--leading-snug);overflow-wrap:anywhere}
.bo-sms-phone-revoked .bo-sms-phone-name h3{color:var(--color-text-secondary)}
.bo-sms-device-id{font-family:var(--font-mono);font-size:var(--text-sm);color:var(--color-text-caption)}
.bo-sms-state{display:inline-flex;align-items:center;height:var(--size-28);padding-inline:var(--space-10);border:1px solid var(--color-border-idle);border-radius:var(--radius-pill);font-size:var(--text-sm);font-weight:var(--weight-semibold);white-space:nowrap}
.bo-sms-state-active{border-color:transparent;background:var(--color-surface-accent-chip);color:var(--color-action-primary)}
.bo-sms-state-silent{border-color:var(--color-feedback-hold-text);background:var(--color-feedback-hold-text);color:var(--color-text-on-action)}
.bo-sms-state-revoked{border-style:dashed;background:transparent;color:var(--color-text-secondary)}
.bo-sms-state-line{margin:0;max-width:none;font-size:var(--text-sm);line-height:var(--leading-normal);color:var(--color-text-secondary)}
.bo-sms-state-line-silent{font-size:var(--text-base);font-weight:var(--weight-semibold);color:var(--color-feedback-hold-text)}
.bo-sms-warnings{display:flex;flex-direction:column;gap:var(--space-8);margin:0;padding:0;list-style:none}
.bo-sms-warning{padding:var(--space-10) var(--space-12);border:1px solid var(--color-border-default);border-radius:var(--radius-card);background:var(--color-surface-sunken);font-size:var(--text-sm);line-height:var(--leading-normal);color:var(--color-text-secondary)}
.bo-sms-warning-danger{border-color:var(--color-border-danger);background:var(--color-surface-problem-soft);color:var(--color-feedback-error-text);font-weight:var(--weight-semibold)}
.bo-sms-facts{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--space-10) var(--space-14);margin:0}
.bo-sms-facts-wide{grid-template-columns:minmax(0,1fr)}
.bo-sms-fact{display:flex;flex-direction:column;gap:var(--space-2);min-width:0}
.bo-sms-fact dt{font-size:var(--text-sm);color:var(--color-text-caption)}
.bo-sms-fact dd{margin:0;font-size:var(--text-sm);color:var(--color-text-primary);overflow-wrap:anywhere}
.bo-sms-counts h4{margin:0 0 var(--space-6);font-size:var(--text-sm);font-weight:var(--weight-semibold);color:var(--color-text-secondary)}
.bo-sms-count-list{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:0 var(--space-14);margin:0}
.bo-sms-count{display:flex;align-items:baseline;justify-content:space-between;gap:var(--space-8);min-width:0;padding-block:var(--space-6);border-bottom:1px solid var(--color-border-default);font-size:var(--text-sm)}
.bo-sms-count dt{min-width:0;color:var(--color-text-secondary)}
.bo-sms-count dd{flex:0 0 auto;margin:0;font-weight:var(--weight-semibold);color:var(--color-text-primary)}
.bo-sms-count-zero dd{font-weight:var(--weight-regular);color:var(--color-text-caption)}
.bo-sms-count-problem dt,.bo-sms-count-problem dd{color:var(--color-feedback-error-text)}
.bo-sms-pairing{margin-top:0}
/* The console's fold has no hover of its own (`.bo-advanced`); this one says it can be opened. */
.bo-sms-pairing > summary:hover{color:var(--color-text-primary)}
.bo-sms-pairing > summary:active{background:var(--color-surface-sunken)}
.bo-sms-pairing[open] > .bo-sms-facts{margin-block:var(--space-4) var(--space-10)}

/* --- The three tables: the console's framed table, stacked on a phone below. --- */
body.backoffice .bo-sms-table{inline-size:100%;min-width:0;border-collapse:collapse}
body.backoffice .bo-sms-table th{text-align:start;white-space:nowrap}
body.backoffice .bo-sms-table td{vertical-align:top;overflow-wrap:anywhere}
.bo-sms-account{display:flex;flex-direction:column;gap:var(--space-2);min-width:0}
.bo-sms-account-id{font-family:var(--font-mono);font-size:var(--text-xs);color:var(--color-text-caption)}
.bo-sms-breaks-value{display:flex;flex-direction:column;gap:var(--space-4);min-width:0}
.bo-sms-breaks strong{font-weight:var(--weight-regular)}
.bo-sms-breaks-some strong{font-weight:var(--weight-semibold);color:var(--color-feedback-error-text)}
.bo-sms-break-why{display:block;max-inline-size:calc(var(--size-150) + var(--space-64));color:var(--color-feedback-error-text)}
.bo-sms-sender{font-weight:var(--weight-semibold)}
.bo-sms-signature{font-size:var(--text-sm)}
body.backoffice .bo-sms-table .bo-sms-action-cell{text-align:end}

/* --- How to pair a phone: a fold that is open while no phone is paired. --- */
.bo-sms-help{margin-top:var(--space-24);border:1px solid var(--color-border-default);border-radius:var(--radius-card-lg);background:var(--color-surface-card)}
.bo-sms-help > summary{display:flex;align-items:center;gap:var(--space-10);min-height:var(--size-48);padding:var(--space-10) var(--space-20);border-radius:var(--radius-card-lg);font-size:var(--text-label);font-weight:var(--weight-semibold);cursor:pointer;list-style:none}
.bo-sms-help > summary::-webkit-details-marker{display:none}
.bo-sms-help > summary::before{content:'';flex:0 0 auto;inline-size:var(--space-8);block-size:var(--space-8);border-inline-end:var(--size-hairline-strong) solid currentColor;border-block-end:var(--size-hairline-strong) solid currentColor;transform:rotate(-45deg)}
.bo-sms-help[open] > summary::before{transform:rotate(45deg)}
.bo-sms-help > summary:hover{background:var(--color-action-ghost-hover)}
.bo-sms-help > summary:active{background:var(--color-surface-sunken)}
.bo-sms-help-body{padding:0 var(--space-20) var(--space-20)}
.bo-sms-steps{display:flex;flex-direction:column;gap:var(--space-20);margin:0;padding-inline-start:var(--space-20)}
.bo-sms-step{display:flex;flex-direction:column;gap:var(--space-10);min-width:0}
.bo-sms-step::marker{font-weight:var(--weight-semibold);color:var(--color-text-secondary)}
.bo-sms-step h3{margin:0;font-size:var(--text-md);font-weight:var(--weight-semibold)}
.bo-sms-step p{margin:0;max-width:78ch;font-size:var(--text-sm);line-height:var(--leading-normal)}
.bo-sms-step .bo-sms-step-lead{margin-top:var(--space-4)}
.bo-sms-code-box{display:flex;flex-direction:column;gap:var(--space-6);min-width:0}
.bo-sms-code{margin:0;padding:var(--space-10) var(--space-12);border:1px solid var(--color-border-default);border-radius:var(--radius-card);background:var(--color-surface-sunken);font-family:var(--font-mono);font-size:var(--text-sm);line-height:var(--leading-normal);color:var(--color-text-primary);white-space:pre-wrap;overflow-wrap:anywhere;word-break:break-all;user-select:all}
.bo-sms-code code{font-family:var(--font-mono)}
.bo-sms-code-actions{display:flex;align-items:center;flex-wrap:wrap;gap:var(--space-6) var(--space-12)}
.bo-sms-copied{font-size:var(--text-sm);color:var(--color-text-secondary)}

/* --- The dialogs: what is being changed, then the reason. --- */
.bo-sms-identity{display:flex;flex-direction:column;gap:var(--space-6);padding:var(--space-12) var(--space-14);border:1px solid var(--color-border-default);border-radius:var(--radius-card);background:var(--color-surface-sunken)}
.bo-sms-identity-row{display:flex;flex-wrap:wrap;justify-content:space-between;gap:var(--space-2) var(--space-12);min-width:0;font-size:var(--text-sm)}
.bo-sms-identity-label{color:var(--color-text-secondary)}
.bo-sms-identity-value{min-width:0;font-weight:var(--weight-semibold);color:var(--color-text-primary);text-align:end;overflow-wrap:anywhere}
.bo-sms-dialog .app-modal-body label :is(input,select)[aria-invalid=true]{border-color:var(--color-action-destructive)}
.bo-sms-error{color:var(--color-feedback-error-text)}
.bo-sms-dialog .app-modal-actions button{min-height:var(--size-44);padding-inline:var(--space-18);font-size:var(--text-sm)}
.bo-sms-dialog .danger-fill{background:var(--color-action-destructive);border-color:var(--color-action-destructive);color:var(--color-text-on-primary)}
/* The operator app's confirm (page-accounts-settings.css `.danger-fill`), the same fill and the
   same darkening on hover, so one destructive confirm looks like every other. */
.bo-sms-dialog .danger-fill:hover,.bo-sms-dialog .danger-fill:active{background:var(--color-action-destructive);border-color:var(--color-action-destructive);color:var(--color-text-on-primary);filter:brightness(0.92)}

/* The tab is the system owner's; `hidden` keeps it off the bar for everyone else (app.css). */
@media (max-width: 1200px){
  .bo-sms-split{grid-template-columns:minmax(0,1fr)}
}
/* A phone: the 16px gutter is the shell's; every control on --size-44, the lead stacked, and
   each table row a stack of label and value instead of a table that scrolls sideways. */
@media (max-width: 860px){
  .bo-sms-refresh,.bo-sms-small{height:var(--size-44);min-height:var(--size-44)}
  .bo-sms-section-head > button{flex:1 1 100%;margin-left:0}
  .bo-sms-lead{flex-direction:column;gap:var(--space-12);padding:var(--space-16)}
  .bo-sms-lead-title{font-size:var(--text-lg)}
  .bo-sms-lead-link{min-block-size:var(--size-44)}
  .bo-sms-phone{padding:var(--space-16)}
  .bo-sms-phone-head .bo-sms-revoke{flex:1 1 100%}
  .bo-sms-help > summary{min-height:var(--size-48);padding-inline:var(--space-16)}
  .bo-sms-help-body{padding:0 var(--space-16) var(--space-16)}
  .bo-sms-frame{position:relative}
  .bo-sms-table,.bo-sms-table tbody,.bo-sms-table tr,body.backoffice .bo-sms-table td{display:block}
  .bo-sms-table thead{position:absolute;inline-size:1px;block-size:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;margin:-1px}
  .bo-sms-table tbody tr{padding:var(--space-8) var(--space-12);border-top:1px solid var(--color-border-default)}
  .bo-sms-table tbody tr:first-child{border-top:0}
  body.backoffice .bo-sms-table td{display:flex;align-items:baseline;justify-content:space-between;gap:var(--space-12);min-width:0;padding:var(--space-6) 0;border-bottom:0;text-align:end}
  body.backoffice .bo-sms-table td::before{content:attr(data-label);flex:0 0 auto;max-inline-size:45%;font-family:var(--font-sans);font-size:var(--text-sm);color:var(--color-text-caption);text-align:start}
  body.backoffice .bo-sms-table td:not([data-label])::before{content:none}
  body.backoffice .bo-sms-table .bo-sms-action-cell{display:block;padding-top:var(--space-8)}
  body.backoffice .bo-sms-table .bo-sms-action-cell .bo-sms-remove{inline-size:100%}
  .bo-sms-account{align-items:flex-end}
  .bo-sms-breaks-value{align-items:flex-end;text-align:end}
  .bo-sms-break-why{max-inline-size:none}
  .bo-sms-dialog .app-modal-actions button{inline-size:100%}
}
/* ===== TICKET 231 END ================================================================ */

/* ===== TICKET 267 (the owner's mockup, 19 ต.ค. 2026): the back office as the mockup's "ดูแลระบบ" ====================
   The mockup's top bar (64 high: the brand, "ระดับระบบ" with "ทุกบริษัท", then "ทุกบริษัท" with its building and the
   account at the end), its page head ("ดูแลระบบ", its line and the "ทุกบริษัท" tag), the sections as its tab row
   under the head (backoffice.js `placeSections`; the drawer keeps them at the compact width), its lead card on the
   landing section and its panel look (the frame radius, a hairline and a faint shadow). Every value is a token. */
.bo-topbar{height:var(--size-64);gap:var(--space-16)}
.bo-mark{width:var(--size-36);height:var(--size-36);border-radius:var(--radius-control);font-size:var(--text-lg)}
.bo-brand-sub{font-size:var(--text-xs);letter-spacing:normal;color:var(--color-text-secondary)}
.bo-scope{display:flex;align-items:center;gap:var(--space-12);margin:0 0 0 var(--space-12);font-size:var(--text-xs);color:var(--color-text-secondary)}
.bo-scope-chip{display:inline-flex;align-items:center;padding:var(--space-4) var(--space-8);border-radius:var(--radius-sm);background:var(--color-surface-sunken);font-size:var(--text-xs);color:var(--color-text-primary);white-space:nowrap}
body.backoffice:has(#workspace[hidden]) .bo-scope,body.backoffice:has(#workspace[hidden]) .bo-all-companies{display:none}
.bo-all-companies{display:inline-flex;align-items:center;gap:var(--space-8);min-height:var(--size-40);padding:var(--space-4) var(--space-8);border-radius:var(--radius-control);color:var(--color-text-link);font-size:var(--text-xs);font-weight:var(--weight-medium);text-decoration:none;white-space:nowrap}
.bo-all-companies:hover{background:var(--color-surface-selected)}
body.backoffice .language-switch{margin-left:auto}
.bo-console-head{display:flex;justify-content:space-between;align-items:flex-start;gap:var(--space-16);margin:0 0 var(--space-24)}
.bo-console-head>div{min-width:0}
.bo-console-name{margin:0;font-size:var(--text-xxl);font-weight:var(--weight-bold);line-height:var(--leading-normal);color:var(--color-text-primary)}
.bo-console-lede{margin:var(--space-8) 0 0;font-size:var(--text-base);color:var(--color-text-secondary)}
@media (min-width: 1201px){
  #workspace>.bo-console{display:block;margin:0 0 var(--space-24);box-shadow:inset 0 -1px 0 var(--color-border-default);overflow-x:auto}
  #workspace>.bo-console .bo-tabs{gap:var(--space-20)}
  #workspace>.bo-console .bo-tabs button{height:auto;min-height:var(--size-44);padding:var(--space-8) var(--space-4);font-size:var(--text-base);font-weight:var(--weight-medium)}
  #workspace>.bo-console .bo-tabs button:hover{background:transparent;color:var(--color-text-primary)}
  #workspace>.bo-console .bo-tabs button[aria-current=page]{color:var(--color-action-primary);font-weight:var(--weight-semibold);border-bottom-color:var(--color-action-primary)}
}
.bo-lead{position:relative;display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:var(--space-24);margin:0 0 var(--space-24);padding:var(--space-28);border:1px solid var(--color-border-default);border-radius:var(--radius-frame);background:var(--color-surface-card);box-shadow:var(--shadow-sm);overflow:hidden}
.bo-lead::before{content:'';position:absolute;inset-block:var(--space-24);inset-inline-start:0;inline-size:var(--space-4);border-radius:var(--radius-pill);background:var(--color-action-primary)}
.bo-lead[data-state=problem]::before{background:var(--color-feedback-error-text)}
.bo-lead h2{margin:0;font-size:var(--text-lg);font-weight:var(--weight-semibold)}
.bo-lead p{margin:var(--space-8) 0 0;max-width:none;font-size:var(--text-sm);color:var(--color-text-secondary)}
.bo-tile,.bo-card,.bo-panel-card{border-radius:var(--radius-frame);box-shadow:var(--shadow-sm)}
.bo-card-draft{box-shadow:none}
@media (max-width: 1200px){
  .bo-scope{display:none}
  .bo-console-head{margin-bottom:var(--space-20)}
  .bo-console-name{font-size:var(--text-xl)}
  .bo-lead{grid-template-columns:minmax(0,1fr);gap:var(--space-16);padding:var(--space-20)}
  .bo-lead .bo-primary{justify-self:stretch;justify-content:center}
}
/* ===== TICKET 267 END ================================================================================================ */
