/* ==========================================================================
   Xi Software - back office
   ==========================================================================

   THE CONTRACT FOR THE INTERFACE.

   One sheet. A class is defined here once and nowhere else. There is no
   <style> block in any back-office template and no style attribute on any
   element, because a rule that lives in a template is invisible to anyone
   reading this file, cannot be reused without copying, and a copy will
   eventually differ from the original.

   The brand tokens, type and control styling come from xi-style.css, which the
   customer portal also loads. What is added here is the vocabulary a dense
   internal interface needs and a customer page does not.

   Every class below is rendered on /style-guide. If a screen needs something
   that is not on that page, it is added HERE and to the guide first, and only
   then used.
   ========================================================================== */

/* --- tokens the back office adds ----------------------------------------
   Layered on the portal's :root rather than redefining it, so the brand stays
   in one place and this file cannot drift from it. */
:root {
  --bo-rule:        #e2e2e2;
  --bo-panel-bg:    #fbfbfb;
  --bo-head-bg:     #f2f2f2;
  --bo-muted:       #6a6a6a;
  --bo-absent:      #8a8a8a;
  --bo-ok:          #17693a;
  --bo-ok-bg:       #eaf5ee;
  --bo-warn:        #8a5a00;
  --bo-warn-bg:     #fdf4e3;
  --bo-stop:        #b30000;
  --bo-stop-bg:     #fff0f0;
  --bo-judgement:   #5a4a8a;
  --bo-judgement-bg:#f1eefb;
  --bo-gap:         1.25rem;
}

/* --- shell ---------------------------------------------------------------
   Absorbed from the customer layout's inline block rather than copied: these
   are the same ideas expressed once, here. */
.bo-topbar   { border-top: 8px solid var(--brand-primary); }
.bo-header   { display: flex; align-items: center; justify-content: space-between;
               flex-wrap: wrap; gap: 1em; padding: 1em 0 0.8em; }
.bo-header .bo-logo { height: 40px; width: auto; display: block; }
.bo-who      { font-size: .95em; color: var(--bo-muted); margin-left: auto; }
.bo-main     { padding-top: .5em; }
.bo-footer   { margin-top: 2.5em; padding: 1.2em 0; border-top: 1px solid var(--bo-rule);
               color: var(--bo-muted); font-size: .95em; }

/* An internal tool says so, on every page, so a screenshot is never mistaken
   for something a customer saw. */
.bo-internal { background: var(--bo-head-bg); border-left: 4px solid var(--brand-accent);
               padding: .4em .8em; font-size: .9em; color: var(--bo-muted); margin: 0 0 1em; }

.bo-nav      { display: flex; flex-wrap: wrap; gap: 1.2em; padding: .6em 0;
               border-bottom: 1px solid var(--bo-rule); margin-bottom: var(--bo-gap); }
.bo-nav a           { text-decoration: none; }
.bo-nav a.bo-here   { font-weight: 600; border-bottom: 2px solid var(--brand-primary); }

/* --- panel: the building block ------------------------------------------ */
.bo-panel        { border: 1px solid var(--bo-rule); background: var(--bo-panel-bg);
                   margin-bottom: var(--bo-gap); }
.bo-panel-head   { display: flex; align-items: baseline; justify-content: space-between;
                   gap: 1em; padding: .55em .9em; background: var(--bo-head-bg);
                   border-bottom: 1px solid var(--bo-rule); }
.bo-panel-title  { font-weight: 600; margin: 0; font-size: 1em; }
.bo-panel-body   { padding: .9em; }
.bo-panel-note   { color: var(--bo-muted); font-size: .92em; margin: .4em 0 0; }

/* Panels side by side where the page is wide enough, stacked where it is not. */
.bo-columns      { display: grid; gap: var(--bo-gap); grid-template-columns: 1fr; }
@media (min-width: 62em) {
  .bo-columns    { grid-template-columns: 1fr 1fr; }
  .bo-wide       { grid-column: 1 / -1; }
}

/* --- detail list: key and value, the shape most reading is --------------- */
.bo-detail            { margin: 0; display: grid; grid-template-columns: 12em 1fr;
                        row-gap: .3em; column-gap: 1em; }
.bo-detail dt         { color: var(--bo-muted); font-weight: normal; }
.bo-detail dd         { margin: 0; }
@media (max-width: 40em) {
  .bo-detail          { grid-template-columns: 1fr; row-gap: 0; }
  .bo-detail dd       { margin: 0 0 .5em; }
}

/* --- absence ------------------------------------------------------------
   The interface says "not recorded" constantly. It must read as a statement
   about the record, never as a failure of the page. */
.bo-absent  { color: var(--bo-absent); font-style: italic; }

/* --- tables: worklists and result lists --------------------------------- */
.bo-table            { width: 100%; border-collapse: collapse; }
.bo-table th         { text-align: left; font-weight: 600; color: var(--bo-muted);
                       border-bottom: 2px solid var(--bo-rule); padding: .4em .6em; }
.bo-table td         { padding: .4em .6em; border-bottom: 1px solid var(--bo-rule); }
.bo-table tr:last-child td { border-bottom: none; }
.bo-table .bo-num    { text-align: right; font-variant-numeric: tabular-nums; }
.bo-table .bo-mono   { font-family: monospace; }
.bo-table tbody tr:hover { background: var(--bo-head-bg); }
.bo-table-empty      { padding: .9em; color: var(--bo-muted); }

/* Two controls that are ONE answer: a count and the unit it is counted in.
   Side by side because '3' and 'years' read as one value and stacking them
   invites reading the second as a separate question. */
.bo-inline           { display: inline-flex; gap: .4em; align-items: center; }
.bo-input-tiny       { width: 5em; }


/* A secret shown ONCE, and never again (ADR 0012): the password an operator
   reads down a telephone. Big, monospaced and letter-spaced because it is going
   to be read ALOUD, and every ambiguous character has to be distinguishable at
   a glance. It gets its own class rather than borrowing .bo-mono, so that a
   later change to table type cannot quietly shrink the one piece of text on the
   screen that nobody can go back and look at again. */
.bo-credential       { font-family: monospace; font-size: 1.5em; letter-spacing: .06em;
                       padding: .6em .8em; margin: .4em 0;
                       background: var(--bo-head-bg); border: 1px solid var(--bo-rule);
                       user-select: all; word-break: break-all; }


/* Depth in a tree, as indentation that is a class rather than a computed
   inline width - the customer navigator computes one, and this file exists so
   the back office does not. */
.bo-depth-1 { padding-left: 0; }
.bo-depth-2 { padding-left: 1.6em; }
.bo-depth-3 { padding-left: 3.2em; }
.bo-depth-4 { padding-left: 4.8em; }

/* --- status pills -------------------------------------------------------
   Every state the estate can be in. Colour is never the only signal: each
   carries its own word. */
.bo-pill          { display: inline-block; padding: .05em .55em; border-radius: 10px;
                    font-size: .85em; border: 1px solid transparent; white-space: nowrap; }
.bo-pill-ok       { color: var(--bo-ok);   background: var(--bo-ok-bg);   border-color: var(--bo-ok); }
.bo-pill-warn     { color: var(--bo-warn); background: var(--bo-warn-bg); border-color: var(--bo-warn); }
.bo-pill-stop     { color: var(--bo-stop); background: var(--bo-stop-bg); border-color: var(--bo-stop); }
.bo-pill-quiet    { color: var(--bo-muted); background: var(--bo-head-bg); border-color: var(--bo-rule); }

/* --- filters: narrowing a list without leaving it ------------------------
   The browse list is the only screen where somebody asks their OWN question,
   so the filters have to read as a set of choices rather than a paragraph of
   links. Grouped by what they narrow, and the chosen one says so - a filter
   you cannot see you applied is how a list comes to look empty for no reason.

   A chip is an ANCHOR, not a button: every filter is a real URL, so the state
   is in the address bar and a useful view can be sent to somebody. */
.bo-filters       { border: 1px solid var(--bo-rule); border-radius: 4px;
                    padding: .5em .7em; margin: .6em 0; background: var(--bo-head-bg); }
.bo-filter-group  { display: flex; flex-wrap: wrap; align-items: baseline;
                    gap: .3em; margin: .25em 0; }
.bo-filter-label  { font-size: .85em; color: var(--bo-muted); min-width: 6.5em; }
.bo-filter        { display: inline-block; padding: .05em .55em; border-radius: 10px;
                    font-size: .85em; text-decoration: none; white-space: nowrap;
                    border: 1px solid var(--bo-rule); color: inherit;
                    background: var(--bo-panel-bg); }
.bo-filter:hover  { border-color: var(--bo-judgement); }
.bo-filter-on     { border-color: var(--bo-judgement); background: var(--bo-judgement-bg);
                    color: var(--bo-judgement); font-weight: 600; }
.bo-filter-count  { color: var(--bo-muted); font-size: .9em; }
.bo-filter-on .bo-filter-count { color: var(--bo-judgement); }

/* The row opener on the browse list: an icon, because the column repeats once
   per row and a word repeated three hundred times is noise. */
.bo-rowopen       { text-decoration: none; font-size: 1.15em; line-height: 1;
                    color: var(--bo-muted); }
.bo-rowopen:hover { color: var(--bo-judgement); }

/* --- provenance: the source affordance ----------------------------------
   On every fact panel, because a citation added anywhere else is a separate
   task, and a separate task is always the next task. */
.bo-source        { font-size: .85em; color: var(--bo-muted); }
.bo-source-ref    { font-family: monospace; }
.bo-source-evidence  { color: var(--bo-ok); }
.bo-source-judgement { color: var(--bo-judgement); background: var(--bo-judgement-bg);
                       padding: .05em .35em; border-radius: 3px; }
.bo-source-none   { color: var(--bo-absent); font-style: italic; }

/* --- forms --------------------------------------------------------------- */
.bo-form            { max-width: 42em; }
.bo-field           { margin-bottom: .9em; }
.bo-field label     { display: block; font-weight: 600; margin-bottom: .2em; }
.bo-field .bo-hint  { display: block; color: var(--bo-muted); font-size: .9em; margin-top: .2em; }
.bo-input, .bo-select, .bo-textarea {
  width: 100%; padding: .4em .5em; border: 1px solid var(--muted-border);
  background: var(--bg); color: var(--text-color); font: inherit;
}
.bo-input:focus, .bo-select:focus, .bo-textarea:focus {
  border: 1px solid var(--brand-primary); outline: 2px solid var(--brand-accent);
}
.bo-input-short     { max-width: 12em; }
.bo-actions         { display: flex; gap: .6em; align-items: center; margin-top: 1em; }

.bo-btn             { padding: .4em 1em; border: 1px solid var(--brand-primary);
                      background: var(--brand-primary); color: #fff; font: inherit;
                      cursor: pointer; }
.bo-btn:hover       { background: var(--brand-accent); border-color: var(--brand-accent); }
.bo-btn-quiet       { background: var(--bg); color: var(--brand-primary); }
.bo-btn-quiet:hover { background: var(--bo-head-bg); color: var(--brand-primary); }
.bo-btn-danger      { background: var(--bo-stop); border-color: var(--bo-stop); }
.bo-btn-danger:hover{ background: #8f0000; border-color: #8f0000; }

/* --- messages ------------------------------------------------------------ */
.bo-msg          { padding: .6em .9em; margin: 0 0 var(--bo-gap); border: 1px solid; }
.bo-msg-ok       { color: var(--bo-ok);   background: var(--bo-ok-bg);   border-color: var(--bo-ok); }
.bo-msg-warn     { color: var(--bo-warn); background: var(--bo-warn-bg); border-color: var(--bo-warn); }
.bo-msg-refused  { color: var(--bo-stop); background: var(--bo-stop-bg); border-color: var(--bo-stop); }

/* A refusal names the operation that IS wanted, where there is one. The model
   already writes those messages; this is where they are shown. */
.bo-msg-refused .bo-instead { display: block; margin-top: .4em; font-weight: 600; }

/* --- the two-step structural change --------------------------------------
   Propose, read what would change, confirm. The command line previews every
   bulk operation and the web is not where that stops. */
.bo-preview        { border: 2px solid var(--bo-warn); background: var(--bo-warn-bg);
                     padding: .9em; margin-bottom: var(--bo-gap); }
.bo-preview-title  { font-weight: 600; margin: 0 0 .5em; color: var(--bo-warn); }
.bo-preview-list   { margin: 0 0 .8em; padding-left: 1.2em; list-style: disc; }
.bo-preview-list li{ margin: .15em 0; }

/* --- search -------------------------------------------------------------- */
.bo-search        { display: flex; gap: .5em; margin-bottom: var(--bo-gap); max-width: 40em; }
.bo-search .bo-input { flex: 1; }
.bo-result-kind   { color: var(--bo-muted); font-size: .85em; text-transform: uppercase;
                    letter-spacing: .04em; }

/* --- print: a rendering that leaves the building ------------------------- */
@media print {
  .bo-nav, .bo-search, .bo-actions, .bo-footer, .bo-internal { display: none; }
  .bo-panel { border: none; background: none; }
  .bo-panel-head { background: none; }
}

/* --- tabs ----------------------------------------------------------------
   The account screen carries eight panels' worth of record. On Xi's own
   account that is 185 Copies and 91 clients, so they are grouped and loaded
   when asked for rather than all at once.

   The tab strip is links, not buttons: each is a real URL that renders the
   whole page with that tab open. The swap is an upgrade on top of that, so the
   screen works either way and can be tested without a browser. */
.bo-tabs        { display: flex; flex-wrap: wrap; gap: .3em; margin: 0 0 -1px;
                  border-bottom: 1px solid var(--bo-rule); }
.bo-tabs a      { padding: .45em 1em; text-decoration: none; border: 1px solid transparent;
                  border-bottom: none; color: var(--bo-muted); }
.bo-tabs a:hover      { background: var(--bo-head-bg); text-decoration: none; }
.bo-tabs a.bo-tab-on  { background: var(--bg); border-color: var(--bo-rule);
                        color: var(--text-color); font-weight: 600; }
.bo-tabpanel    { border: 1px solid var(--bo-rule); border-top: none;
                  padding: var(--bo-gap); background: var(--bg); }
.bo-tab-loading { color: var(--bo-muted); }

/* --- hierarchy -----------------------------------------------------------
   Who an account buys through, and who buys through it. Both directions,
   because an account is defined as much by one as the other. */
.bo-chain       { margin: 0 0 .8em; }
.bo-chain li    { list-style: none; margin: 0; }
.bo-chain-up    { color: var(--bo-muted); }
.bo-chain-self  { font-weight: 600; }
.bo-chain-arrow { color: var(--bo-muted); }

/* --- modal ----------------------------------------------------------------
   For creating or amending ONE record's own fields, where context is the point:
   "add a customer here" from a distributor's page should not lose the
   distributor's page.

   NOT for anything that moves or ends something. Those are full pages with a
   preview, because the reading is the safety and a preview inside a modal
   invites scrolling past it.

   Native <dialog>, so focus trapping, the backdrop and Escape are the browser's
   job rather than ours. */
.bo-modal            { border: 1px solid var(--bo-rule); padding: 0; width: min(48em, 92vw);
                       background: var(--bg); color: var(--text-color); }
.bo-modal::backdrop  { background: rgba(0, 0, 0, .35); }
.bo-modal-head       { display: flex; align-items: baseline; justify-content: space-between;
                       gap: 1em; padding: .6em .9em; background: var(--bo-head-bg);
                       border-bottom: 1px solid var(--bo-rule); }
.bo-modal-title      { font-weight: 600; margin: 0; font-size: 1.05em; }
.bo-modal-close      { border: none; background: none; font: inherit; cursor: pointer;
                       color: var(--bo-muted); padding: 0 .2em; }
.bo-modal-close:hover{ color: var(--text-color); }
.bo-modal-body       { padding: .9em; max-height: 70vh; overflow-y: auto; }

/* --- breadcrumb ----------------------------------------------------------
   Where am I. Every record here has exactly one parent - a Copy belongs to an
   account, a machine to a Copy, an account to its distributor - and a screen
   reached from a search otherwise gives no clue how it relates to anything. */
.bo-crumbs        { margin: 0 0 .8em; font-size: .95em; color: var(--bo-muted); }
.bo-crumbs a      { text-decoration: none; }
.bo-crumbs a:hover{ text-decoration: underline; }
.bo-crumb-sep     { padding: 0 .45em; color: var(--bo-absent); }
.bo-crumb-kind    { font-size: .82em; text-transform: uppercase; letter-spacing: .04em;
                    color: var(--bo-absent); padding-right: .35em; }
.bo-crumb-here    { color: var(--text-color); font-weight: 600; }

/* --- disclosure ----------------------------------------------------------
   A panel that starts closed and loads when it is opened, so what it shows is
   what is true now rather than what was true when the page was drawn. Closing
   empties it, so opening again is a fresh read.

   Native <details>, so the keyboard and the open state are the browser's job. */
.bo-disclosure          { border: 1px solid var(--bo-rule); background: var(--bo-panel-bg);
                          margin-bottom: var(--bo-gap); }
.bo-disclosure > summary{ padding: .55em .9em; background: var(--bo-head-bg); cursor: pointer;
                          font-weight: 600; list-style: none; display: flex;
                          justify-content: space-between; align-items: baseline; gap: 1em; }
.bo-disclosure > summary::-webkit-details-marker { display: none; }
.bo-disclosure > summary::after  { content: '\25B8'; color: var(--bo-muted); }
.bo-disclosure[open] > summary::after { content: '\25BE'; }
.bo-disclosure > summary:hover   { background: var(--bo-rule); }
.bo-disclosure-note     { font-weight: normal; font-size: .9em; color: var(--bo-muted); }
.bo-disclosure-body     { padding: .9em; }

/* A filter that belongs to ONE open group, not to the panel. Searching a tree
   from the outside searches branches the reader has not opened and cannot see
   the result of; this one appears inside a group when it is opened and filters
   only that group's rows. */
.bo-treefilter          { width: 100%; box-sizing: border-box; margin-bottom: .6em;
                          padding: .4em .6em; border: 1px solid var(--bo-rule);
                          background: var(--bg); color: var(--text-color); }
.bo-treegroup .bo-table { margin: 0; }

/* A CHOICE FROM WHAT THE RECORD ALREADY HOLDS, one per line. Used where an
   amendment is a selection rather than typing - placing Copies under a
   Schedule's cap - because the thing being chosen has to stay readable while
   several are chosen. */
.bo-check               { display: block; padding: .25em 0; }
.bo-check input         { margin-right: .5em; }

/* THE ACCOUNT A RECORD BELONGS TO, under its heading and above its pills. The
   record pages used to put a bare custid on the same line as the state, so the
   pill read as though it qualified the account. */
.bo-record-owner        { margin: -.4em 0 .6em; font-size: 1.05em; }
