/* /Components/Layout/AutoApproveSettings.razor.rz.scp.css */
/* Copies of the panel's own section styles, not a reference to them.

   Blazor scopes a .razor.css file to its own component, so .panel-section, .panel-title and
   .toggle-row in Diagnose.razor.css cannot reach this markup: the scope attribute differs. They
   are duplicated here deliberately rather than lifted into app.css, because app.css is the
   shell's stylesheet and these are a panel section's. If a third panel section ever wants them,
   that is the point to move all three copies into one place rather than make a fourth. */

/* The divider above this section. .panel-section + .panel-section in Diagnose.razor.css draws it
   between the sections that live there, but a sibling selector cannot see across a component
   boundary, so this section draws its own. It is always last in the panel, so the rule is
   unconditional rather than adjacency-based. */
.panel-section[b-kv1yp7spuu] {
  margin-top: 1.1rem;
  padding-top: .9rem;
  border-top: 1px solid #e5e7eb;
}

.panel-section summary[b-kv1yp7spuu] {
  cursor: pointer;
}

.panel-title[b-kv1yp7spuu] {
  margin: 0 0 .4rem;
  font-size: .95rem;
  font-weight: 600;
}

/* padding-right pulls the checkbox in off the panel's edge. space-between puts it against
   whatever the row's right edge is, and the panel's own .9rem was not enough clearance, so the
   column of boxes sat on the border. The label keeps the row's full left edge. */
.toggle-row[b-kv1yp7spuu] {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
  padding: .35rem 50px .35rem 0;
  font-size: .85rem;
  cursor: pointer;
}

/* Matches the Model section's labels (.inv dt in ModelSettings.razor.css). These are labels for
   their controls exactly as those are labels for their values, and reading down the panel the
   two sections should look like one list.

   The weight is not redundant. Those labels are <dt>, and Bootstrap's reboot gives every dt
   font-weight: 700 — so they are bold for a reason nothing in this project's own CSS mentions,
   and a <span> here starts at 400. Setting the grey alone left these visibly lighter. */
.toggle-row > span[b-kv1yp7spuu] {
  color: #6b7280;
  font-weight: 700;
}

.toggle-row input[b-kv1yp7spuu] {
  cursor: pointer;
}
/* /Components/Layout/MainLayout.razor.rz.scp.css */
/* The shell's own styles are global, in wwwroot/app.css, for two reasons. They use :has() to
   decide whether a right panel exists at all, and Blazor's CSS isolation rewriter appends a
   scope attribute to selectors in ways that :has() does not survive predictably. And the
   script that drives the burger and the resizer sets classes on <html>, which scoped CSS
   cannot reach.

   What is left here is the error banner, which belongs to this component and nothing else. */

#blazor-error-ui[b-d3ndpql2dd] {
    color-scheme: light only;
    background: lightyellow;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    box-sizing: border-box;
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}

    #blazor-error-ui .dismiss[b-d3ndpql2dd] {
        cursor: pointer;
        position: absolute;
        right: 0.75rem;
        top: 0.5rem;
    }
/* /Components/Layout/ModelSettings.razor.rz.scp.css */
/* Copies of the panel's own section styles, not a reference to them — the same situation
   AutoApproveSettings.razor.css documents, arriving for the second time.

   Blazor scopes a .razor.css file to its own component, so .inv, .panel-title, .panel-section
   and .muted in Diagnose.razor.css cannot reach this markup: the scope attribute differs. This
   section used to live in Diagnose and inherited all of them; moving it here for the Reasoning
   Level dropdown took its styling away with no other visible sign, which is the failure mode
   worth naming — the markup was moved verbatim and still rendered differently.

   **This is the third copy, and AutoApproveSettings.razor.css says the third is the point to
   consolidate rather than make a fourth.** It has not been done here, deliberately: lifting
   these into app.css means touching the two existing copies as well, and the adjacency rule
   below does not survive the move unchanged. Worth doing as its own change, with the page in
   front of you. */

/* The divider above this section. Diagnose.razor.css draws it with .panel-section +
   .panel-section, but a sibling selector cannot see across a component boundary: this section
   is the first thing RightPanelInteractive mounts, and its previous sibling (Worker) is
   rendered by Diagnose. So it draws its own, unconditionally, exactly as the section below it
   does. */
.panel-section[b-yrs0i6o4ym] {
  margin-top: 1.1rem;
  padding-top: .9rem;
  border-top: 1px solid #e5e7eb;
}

.panel-section summary[b-yrs0i6o4ym] {
  cursor: pointer;
}

.panel-section > p[b-yrs0i6o4ym] {
  margin: 0 0 .75rem;
}

/* .75rem, matching Diagnose's .panel-title rather than AutoApproveSettings' .4rem: this
   section came from Diagnose and should keep looking like it did there. */
.panel-title[b-yrs0i6o4ym] {
  margin: 0 0 .75rem;
  font-size: .95rem;
  font-weight: 600;
}

/* Two columns so labels and values line up down the edge, which is what makes a spec sheet
   scannable rather than a list of sentences. */
.inv[b-yrs0i6o4ym] {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: .3rem .75rem;
  margin: 0 0 .75rem;
  font-size: .85rem;
}

.inv dt[b-yrs0i6o4ym] {
  color: #6b7280;
  white-space: nowrap;
}

.inv dd[b-yrs0i6o4ym] {
  margin: 0;
  overflow-wrap: anywhere;
}

.inv-when[b-yrs0i6o4ym] {
  margin: 0 0 .75rem;
}

.muted[b-yrs0i6o4ym] {
  color: #6b7280;
  font-size: .875rem;
}

/* The Reasoning Level label. Now that it sits in the same grid as the facts above, it takes
   .inv dt's grey along with their column — a darker label stood out as the only heavy thing in
   the list. Only the vertical centring and the pointer are its own, because its value is a
   control rather than text. */
.inv dt.choice[b-yrs0i6o4ym] {
  align-self: center;
  cursor: pointer;
}

/* A select sizes to its longest option, so it needs its own type size or it sits taller than
   the rows above it. */
.inv dd select[b-yrs0i6o4ym] {
  font-size: .85rem;
  padding: .15rem .3rem;
  cursor: pointer;
}
/* /Components/Layout/NavMenu.razor.rz.scp.css */
/* The burger and the brand live in the shell's top bar now. What is left here is the links. */

.bi[b-3fnk27u0ly] {
    display: inline-block;
    position: relative;
    width: 1.25rem;
    height: 1.25rem;
    margin-right: 0.75rem;
    top: -1px;
    background-size: cover;
}

.bi-house-door-fill-nav-menu[b-3fnk27u0ly] {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-house-door-fill' viewBox='0 0 16 16'%3E%3Cpath d='M6.5 14.5v-3.505c0-.245.25-.495.5-.495h2c.25 0 .5.25.5.5v3.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.146-.354L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293L8.354 1.146a.5.5 0 0 0-.708 0l-6 6A.5.5 0 0 0 1.5 7.5v7a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5Z'/%3E%3C/svg%3E");
}

.bi-plus-square-fill-nav-menu[b-3fnk27u0ly] {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-plus-square-fill' viewBox='0 0 16 16'%3E%3Cpath d='M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2zm6.5 4.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3a.5.5 0 0 1 1 0z'/%3E%3C/svg%3E");
}

.bi-list-nested-nav-menu[b-3fnk27u0ly] {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-list-nested' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M4.5 11.5A.5.5 0 0 1 5 11h10a.5.5 0 0 1 0 1H5a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 3 7h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 1 3h10a.5.5 0 0 1 0 1H1a.5.5 0 0 1-.5-.5z'/%3E%3C/svg%3E");
}

.bi-chat-dots-fill-nav-menu[b-3fnk27u0ly] {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-chat-dots-fill' viewBox='0 0 16 16'%3E%3Cpath d='M16 8c0 3.866-3.582 7-8 7a9.06 9.06 0 0 1-2.347-.306c-.584.296-1.925.864-4.181 1.234-.2.032-.352-.176-.273-.362.354-.836.674-1.95.77-2.966C.744 11.37 0 9.76 0 8c0-3.866 3.582-7 8-7s8 3.134 8 7zM5 8a1 1 0 1 0-2 0 1 1 0 0 0 2 0zm4 0a1 1 0 1 0-2 0 1 1 0 0 0 2 0zm3 1a1 1 0 1 0 0-2 1 1 0 0 0 0 2z'/%3E%3C/svg%3E");
}

.nav-item[b-3fnk27u0ly] {
    font-size: 0.9rem;
    padding-bottom: 0.5rem;
}

    .nav-item:first-of-type[b-3fnk27u0ly] {
        padding-top: 1rem;
    }

    .nav-item:last-of-type[b-3fnk27u0ly] {
        padding-bottom: 1rem;
    }

    .nav-item[b-3fnk27u0ly]  .nav-link {
        color: #d7d7d7;
        background: none;
        border: none;
        border-radius: 4px;
        height: 3rem;
        display: flex;
        align-items: center;
        line-height: 3rem;
        width: 100%;
    }

.nav-item[b-3fnk27u0ly]  a.active {
    background-color: rgba(255,255,255,0.37);
    color: white;
}

.nav-item[b-3fnk27u0ly]  .nav-link:hover {
    background-color: rgba(255,255,255,0.1);
    color: white;
}

/* Always laid out. The column it sits in is what collapses, so the links do not need to
   disappear and reappear underneath it. */
.nav-scrollable[b-3fnk27u0ly] {
    display: block;
    height: calc(100vh - 3rem);
    overflow-y: auto;

    /* Reserve the scrollbar's space whether or not there is a scrollbar.

       overflow-y: auto means the bar appears only when the menu is taller than the viewport,
       and how tall the menu is depends on the page: OwnedSessions renders a row per open
       session and nothing at all when there are none, and it is interactive inside a static
       menu, so its rows arrive after first paint rather than with it. The links are laid out
       inside this box, so the bar arriving takes about 15px off them and the whole menu jogs
       left — on some pages, at some moments, and not others.

       stable keeps the gutter there permanently. The menu is then the same width on every page
       and while a session opens or closes. */
    scrollbar-gutter: stable;

    /* **No width here.** It is set in app.css, with the rest of the shell's geometry, because
       the width now tracks --nav-w and --nav-w is driven by the resize handle. Declaring it in
       both files is worse than it sounds: this stylesheet is scoped, so its selector gains an
       attribute and its <link> comes after app.css, which means whatever is written here wins
       silently over the file that owns the column it has to agree with. */
}
/* /Components/Layout/OwnedSessions.razor.rz.scp.css */
/* The technician's own open sessions, under the nav links and above the search box.

   ::deep throughout: NavLink renders its own anchor, so the scope attribute never lands on it,
   and reaching it any other way silently does nothing. NavMenu.razor.css reaches .nav-link the
   same way for the same reason. */

.nav-sessions[b-fobdoqag1d] {
    border-top: 1px solid rgba(255, 255, 255, .15);
    padding-top: .75rem;
}

.nav-sessions-title[b-fobdoqag1d] {
    font-size: .7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: #cbd5e1;
    margin: 0 0 .35rem;
}

.nav-sessions ul[b-fobdoqag1d] {
    list-style: none;
    margin: 0;
    padding: 0;
}

.nav-sessions[b-fobdoqag1d]  .nav-session {
    display: flex;
    align-items: center;
    gap: .45rem;
    padding: .3rem .4rem;
    border-radius: .25rem;
    color: #d7d7d7;
    text-decoration: none;
    font-size: .85rem;
}

    .nav-sessions[b-fobdoqag1d]  .nav-session:hover {
        background: rgba(255, 255, 255, .1);
        color: #fff;
    }

    /* Matches the nav links' own active treatment, so the session you are on reads as the
       selected item in the panel rather than as a second, competing kind of highlight. */
    .nav-sessions[b-fobdoqag1d]  .nav-session.active {
        background: rgba(255, 255, 255, .37);
        color: #fff;
    }

/* flex-shrink: 0 so a long hostname squeezes the name and never the dot. The dot is the only
   part of the row worth seeing from across a workshop. */
.nav-sessions[b-fobdoqag1d]  .dot {
    width: .5rem;
    height: .5rem;
    border-radius: 50%;
    background: #6b7280;
    flex-shrink: 0;
}

    .nav-sessions[b-fobdoqag1d]  .dot-attention {
        background: var(--brand-orange);
    }

/* One line per session. A name that does not fit is cut rather than wrapped: this is a
   switcher, and a row that grows to two lines costs more than the tail of a hostname is worth. */
.nav-sessions[b-fobdoqag1d]  .nav-session-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* /Components/Layout/ReconnectModal.razor.rz.scp.css */
.components-reconnect-first-attempt-visible[b-7kkcxswdzl],
.components-reconnect-repeated-attempt-visible[b-7kkcxswdzl],
.components-reconnect-failed-visible[b-7kkcxswdzl],
.components-pause-visible[b-7kkcxswdzl],
.components-resume-failed-visible[b-7kkcxswdzl],
.components-rejoining-animation[b-7kkcxswdzl] {
    display: none;
}

#components-reconnect-modal.components-reconnect-show .components-reconnect-first-attempt-visible[b-7kkcxswdzl],
#components-reconnect-modal.components-reconnect-show .components-rejoining-animation[b-7kkcxswdzl],
#components-reconnect-modal.components-reconnect-paused .components-pause-visible[b-7kkcxswdzl],
#components-reconnect-modal.components-reconnect-resume-failed .components-resume-failed-visible[b-7kkcxswdzl],
#components-reconnect-modal.components-reconnect-retrying[b-7kkcxswdzl],
#components-reconnect-modal.components-reconnect-retrying .components-reconnect-repeated-attempt-visible[b-7kkcxswdzl],
#components-reconnect-modal.components-reconnect-retrying .components-rejoining-animation[b-7kkcxswdzl],
#components-reconnect-modal.components-reconnect-failed[b-7kkcxswdzl],
#components-reconnect-modal.components-reconnect-failed .components-reconnect-failed-visible[b-7kkcxswdzl] {
    display: block;
}


#components-reconnect-modal[b-7kkcxswdzl] {
    background-color: white;
    width: 20rem;
    margin: 20vh auto;
    padding: 2rem;
    border: 0;
    border-radius: 0.5rem;
    box-shadow: 0 3px 6px 2px rgba(0, 0, 0, 0.3);
    opacity: 0;
    transition: display 0.5s allow-discrete, overlay 0.5s allow-discrete;
    animation: components-reconnect-modal-fadeOutOpacity-b-7kkcxswdzl 0.5s both;
    &[open]

{
    animation: components-reconnect-modal-slideUp-b-7kkcxswdzl 1.5s cubic-bezier(.05, .89, .25, 1.02) 0.3s, components-reconnect-modal-fadeInOpacity-b-7kkcxswdzl 0.5s ease-in-out 0.3s;
    animation-fill-mode: both;
}

}

#components-reconnect-modal[b-7kkcxswdzl]::backdrop {
    background-color: rgba(0, 0, 0, 0.4);
    animation: components-reconnect-modal-fadeInOpacity-b-7kkcxswdzl 0.5s ease-in-out;
    opacity: 1;
}

@keyframes components-reconnect-modal-slideUp-b-7kkcxswdzl {
    0% {
        transform: translateY(30px) scale(0.95);
    }

    100% {
        transform: translateY(0);
    }
}

@keyframes components-reconnect-modal-fadeInOpacity-b-7kkcxswdzl {
    0% {
        opacity: 0;
    }

    100% {
        opacity: 1;
    }
}

@keyframes components-reconnect-modal-fadeOutOpacity-b-7kkcxswdzl {
    0% {
        opacity: 1;
    }

    100% {
        opacity: 0;
    }
}

.components-reconnect-container[b-7kkcxswdzl] {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1rem;
}

#components-reconnect-modal p[b-7kkcxswdzl] {
    margin: 0;
    text-align: center;
}

#components-reconnect-modal button[b-7kkcxswdzl] {
    border: 0;
    background-color: #6b9ed2;
    color: white;
    padding: 4px 24px;
    border-radius: 4px;
}

    #components-reconnect-modal button:hover[b-7kkcxswdzl] {
        background-color: #3b6ea2;
    }

    #components-reconnect-modal button:active[b-7kkcxswdzl] {
        background-color: #6b9ed2;
    }

.components-rejoining-animation[b-7kkcxswdzl] {
    position: relative;
    width: 80px;
    height: 80px;
}

    .components-rejoining-animation div[b-7kkcxswdzl] {
        position: absolute;
        border: 3px solid #0087ff;
        opacity: 1;
        border-radius: 50%;
        animation: components-rejoining-animation-b-7kkcxswdzl 1.5s cubic-bezier(0, 0.2, 0.8, 1) infinite;
    }

        .components-rejoining-animation div:nth-child(2)[b-7kkcxswdzl] {
            animation-delay: -0.5s;
        }

@keyframes components-rejoining-animation-b-7kkcxswdzl {
    0% {
        top: 40px;
        left: 40px;
        width: 0;
        height: 0;
        opacity: 0;
    }

    4.9% {
        top: 40px;
        left: 40px;
        width: 0;
        height: 0;
        opacity: 0;
    }

    5% {
        top: 40px;
        left: 40px;
        width: 0;
        height: 0;
        opacity: 1;
    }

    100% {
        top: 0px;
        left: 0px;
        width: 80px;
        height: 80px;
        opacity: 0;
    }
}
/* /Components/Machines/ConnectionButton.razor.rz.scp.css */
.conn[b-axgk29v249] {
    min-width: 6.5rem;
    padding: 0.2rem 0.6rem;
    border: 1px solid transparent;
    border-radius: 0.25rem;
    font-size: 0.85rem;
    font-weight: 600;
    cursor: pointer;
}

.conn-session[b-axgk29v249] {
    background: #ffc107;
    border-color: #e0a800;
    color: #3d2e00;
}

.conn-available[b-axgk29v249] {
    background: #198754;
    border-color: #146c43;
    color: #fff;
}

/* Still a button so the column reads the same on every row; just nothing to press.

   Light grey rather than the red it used to be. A machine that is switched off, or out of the
   office, or simply not plugged in, is the ordinary state of most of the fleet most of the
   time -- it is not a fault, and a column of red buttons said otherwise every time a technician
   opened the page. Grey recedes, which is what a row with nothing to do on it should do, and it
   leaves red meaning something has actually gone wrong (see .conn-error below).

   Dark text, because the background is now light: white on #e5e7eb is unreadable. */
.conn-offline[b-axgk29v249],
.conn-offline:disabled[b-axgk29v249] {
    background: #e5e7eb;
    border-color: #d1d5db;
    color: #4b5563;
    cursor: default;
    opacity: 1;
}

.conn:disabled:not(.conn-offline)[b-axgk29v249] {
    opacity: 0.6;
    cursor: default;
}

.conn-error[b-axgk29v249] {
    margin-left: 0.5rem;
    font-size: 0.8rem;
    color: #b02a37;
}
/* /Components/Machines/MachineNotesEditor.razor.rz.scp.css */
/* Machine Notes pane on the machine page. */
.notes-pane[b-0fjbnmzx7u] {
  border: 1px solid #e5e7eb;
  border-radius: .35rem;
  padding: 1rem 1.1rem;
  background: #fafafa;
}

.notes-pane h2[b-0fjbnmzx7u] {
  font-size: 1.1rem;
  margin: 0 0 .5rem;
}

.notes-help[b-0fjbnmzx7u],
.notes-example[b-0fjbnmzx7u] {
  font-size: .875rem;
  margin: 0 0 .6rem;
}

.notes-example[b-0fjbnmzx7u] {
  padding: .5rem .65rem;
  border-left: 3px solid #1b6ec2;
  background: #fff;
}

.notes-list[b-0fjbnmzx7u] {
  list-style: none;
  padding: 0;
  margin: .75rem 0;
}

.notes-list li[b-0fjbnmzx7u] {
  padding: .6rem 0;
  border-top: 1px solid #e5e7eb;
}

.notes-body[b-0fjbnmzx7u] {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.notes-meta[b-0fjbnmzx7u] {
  font-size: .75rem;
  margin-top: .2rem;
}

.notes-new[b-0fjbnmzx7u] {
  display: block;
  font-weight: 600;
  margin-top: .5rem;
}

textarea[b-0fjbnmzx7u] {
  display: block;
  width: 100%;
  margin-top: .25rem;
  padding: .4rem;
  font: inherit;
  font-weight: normal;
  border: 1px solid #ced4da;
  border-radius: .25rem;
  resize: vertical;
}

.notes-actions[b-0fjbnmzx7u] {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .5rem;
  margin-top: .4rem;
  font-size: .85rem;
}

.notes-actions button[b-0fjbnmzx7u] {
  padding: .3rem .8rem;
  font-size: .85rem;
  border: 1px solid #ced4da;
  border-radius: .25rem;
  background: #fff;
  cursor: pointer;
}

.notes-actions button.primary[b-0fjbnmzx7u] {
  border-color: #1b6ec2;
  background: #1b6ec2;
  color: #fff;
}

.notes-actions button.danger-button[b-0fjbnmzx7u] {
  border-color: #b02a37;
  background: #b02a37;
  color: #fff;
}

.notes-actions button:disabled[b-0fjbnmzx7u] {
  opacity: .5;
  cursor: default;
}

.muted[b-0fjbnmzx7u] {
  color: #6b7280;
}

.notes-hint[b-0fjbnmzx7u] {
  font-size: .75rem;
  margin: .6rem 0 0;
}

.notice[b-0fjbnmzx7u] {
  padding: .5rem .7rem;
  border-radius: .25rem;
}

.notice-error[b-0fjbnmzx7u] {
  background-color: #f8d7da;
  color: #842029;
}
/* /Components/Machines/MachineTable.razor.rz.scp.css */
.work-section[b-ks7bc3zqu0] {
    margin-bottom: 2rem;
}

.work-section h2[b-ks7bc3zqu0] {
    font-size: 1.1rem;
    margin-bottom: 0.5rem;
}

.count[b-ks7bc3zqu0] {
    display: inline-block;
    min-width: 1.5rem;
    padding: 0 0.4rem;
    border-radius: 1rem;
    background: #e9ecef;
    color: #495057;
    font-size: 0.8rem;
    text-align: center;
    vertical-align: middle;
}

/* Each table scrolls on its own, header pinned, so one long list never pushes the next table
   off the screen. */
.work-scroll[b-ks7bc3zqu0] {
    max-height: 18rem;
    overflow-y: auto;
    border: 1px solid #e5e5e5;
    border-radius: 0.25rem;
}

.work[b-ks7bc3zqu0] {
    width: 100%;
    border-collapse: collapse;
}

.work th[b-ks7bc3zqu0],
.work td[b-ks7bc3zqu0] {
    text-align: left;
    padding: 0.4rem 0.75rem;
    border-bottom: 1px solid #eee;
    vertical-align: middle;
    white-space: nowrap;
}

.work th[b-ks7bc3zqu0] {
    position: sticky;
    top: 0;
    background: #f8f9fa;
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: #6c757d;
    z-index: 1;
}
/* /Components/Markup/RichText.razor.rz.scp.css */
/* Tables from the model are data, not layout: narrow, ruled, readable at a glance in a
   transcript column that is already competing with the machine panel for width. */
.rt-table-scroll[b-t2nt55h4d2] {
  /* A wide table scrolls itself rather than widening the transcript. Without this, one
     six-column table from the model stretches .shell-content and puts a horizontal scrollbar
     under the entire chat — including every message that fits perfectly well. */
  overflow-x: auto;
  margin: .5rem 0;
}

.rt-table[b-t2nt55h4d2] {
  border-collapse: collapse;
  font-size: .85rem;
  /* auto, not 100%: a two-column table stretched across the full width separates its own
     columns by an expanse of nothing, which is harder to read than a compact one. */
  width: auto;
  max-width: 100%;
}

.rt-table th[b-t2nt55h4d2],
.rt-table td[b-t2nt55h4d2] {
  border: 1px solid #e5e7eb;
  padding: .3rem .55rem;
  vertical-align: top;
}

.rt-table thead th[b-t2nt55h4d2] {
  background: #f9fafb;
  font-weight: 600;
  /* Not sticky. A sticky header here would stick to .shell-content's scrollport, not to the
     table, so it would float over the messages above it once the table scrolled past — which
     looks like a bug rather than a convenience. Transcript tables are short. */
}

.rt-table tbody tr:nth-child(even) td[b-t2nt55h4d2] {
  background: #fcfcfd;
}

.rt-left[b-t2nt55h4d2] { text-align: left; }
.rt-right[b-t2nt55h4d2] { text-align: right; }
.rt-center[b-t2nt55h4d2] { text-align: center; }

.rt-list[b-t2nt55h4d2] {
  margin: .25rem 0;
  padding-left: 1.25rem;
}

.rt-list li[b-t2nt55h4d2] { margin: .15rem 0; }

.rt-code[b-t2nt55h4d2] {
  background: #f3f4f6;
  border-radius: .2rem;
  padding: .05rem .3rem;
  font-size: .85em;
}

/* Matches .entry p in Diagnose.razor.css, which no longer reaches these paragraphs now that
   they are rendered by this component and carry its own scope attribute instead. */
p[b-t2nt55h4d2] {
  margin: .25rem 0;
  white-space: pre-wrap;
}
/* /Components/Pages/Customers.razor.rz.scp.css */
/* The Customers page. Same shape as the work-page table (MachineTable.razor.css): one
   scrolling body with the header pinned, so a long list scrolls inside the page rather than
   taking the search box off the top of the screen with it. */

.cust-tools[b-4fipw6f2bn] {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin-bottom: 0.75rem;
}

.cust-search[b-4fipw6f2bn] {
    flex: 0 1 22rem;
    padding: 0.4rem 0.6rem;
    font-size: 1rem;
    border: 1px solid #ced4da;
    border-radius: 0.25rem;
}

/* The same pill the work page puts beside a table's heading. It counts what is on screen,
   not what the shop has, which is the number that matters while a search is narrowing. */
.count[b-4fipw6f2bn] {
    display: inline-block;
    min-width: 1.5rem;
    padding: 0 0.4rem;
    border-radius: 1rem;
    background: #e9ecef;
    color: #495057;
    font-size: 0.8rem;
    text-align: center;
}

.cust-tools .edit-link[b-4fipw6f2bn] {
    margin-left: auto;
    font-size: 0.9rem;
}

.cust-scroll[b-4fipw6f2bn] {
    max-height: 32rem;
    overflow-y: auto;
    border: 1px solid #e5e5e5;
    border-radius: 0.25rem;
}

.cust[b-4fipw6f2bn] {
    width: 100%;
    border-collapse: collapse;
}

.cust th[b-4fipw6f2bn],
.cust td[b-4fipw6f2bn] {
    text-align: left;
    padding: 0.4rem 0.75rem;
    border-bottom: 1px solid #eee;
    vertical-align: middle;
    white-space: nowrap;
}

.cust th[b-4fipw6f2bn] {
    position: sticky;
    top: 0;
    background: #f8f9fa;
    z-index: 1;
    padding: 0;
}

/* The header's button fills its cell, so the whole header is the target and not just the
   word in it. Stripped back to the text: it has to look like a column heading, because it is
   one, and the arrow is what says it can be clicked. */
.cust th .sort[b-4fipw6f2bn] {
    display: block;
    width: 100%;
    padding: 0.4rem 0.75rem;
    border: 0;
    background: none;
    font: inherit;
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: #6c757d;
    text-align: inherit;
    cursor: pointer;
}

.cust th .sort:hover[b-4fipw6f2bn] {
    color: #212529;
}

.cust th .arrow[b-4fipw6f2bn] {
    /* Reserved whether or not this column is the sorted one, so clicking a header does not
       shift the row of headings sideways. */
    display: inline-block;
    min-width: 0.75rem;
    margin-left: 0.25rem;
}

.cust th.num[b-4fipw6f2bn],
.cust td.num[b-4fipw6f2bn] {
    text-align: right;
}

.cust tr.inactive td[b-4fipw6f2bn] {
    color: #9a9a9a;
}

.cust .actions[b-4fipw6f2bn] {
    text-align: right;
}

.cust .actions .edit-link[b-4fipw6f2bn] {
    font-size: 0.85rem;
}

/* .muted has no global rule -- the only one in the solution lives inside Diagnose.razor.css
   and scoped CSS does not leave its own component, so every .muted elsewhere renders at full
   strength. Given here so that "No customers match that search." reads as an aside rather
   than as a row.

   The .tag family is global, in app.css, and applies here as it does on the technicians
   page. */
.cust .muted[b-4fipw6f2bn] {
    color: #6b7280;
}
/* /Components/Pages/Diagnose.razor.rz.scp.css */
/* The chat layout: transcript scrolls in the normal page flow, the dock at the bottom does
   not. session-view is a flex column tall enough to fill the screen under the shell bar
   (3rem) and shell-content's own padding (1rem top, 2rem bottom — app.css, .shell-content), so
   a short transcript still parks the dock at the bottom of the viewport instead of leaving it
   stranded right under the last message. margin-top: auto on .dock is what does that parking;
   position: sticky is what keeps the dock pinned to the viewport bottom once the transcript is
   long enough that the page scrolls — the same trick the shell already uses for its top bar,
   just at the other edge, so there is no second scroll container to keep in sync. */
.session-view[b-bhiodez556] {
  display: flex;
  flex-direction: column;
  min-height: calc(100vh - 6rem);
}

.dock[b-bhiodez556] {
  margin-top: auto;
  position: sticky;
  bottom: 0;
  background: #3f3f46;
  padding: 10px;
  box-shadow: 0 -2px 8px rgba(0, 0, 0, .2);
}

/* The dark background's bleed past .dock's own box, out through .shell-content's padding
   (app.css) so it reaches the panel's true edges — full width, flush with the bottom, no
   gap for the panel's own background to show through below it.
   A decorative ::before rather than negative margins on .dock itself: .dock is
   position: sticky, and a negative margin on a sticky element changes the box browsers use
   to compute its "stuck" position — that's what let the dark box creep up and cover the
   last transcript messages. ::before is absolutely positioned (anchored to .dock, itself a
   positioned element) and z-index: -1 keeps it behind .dock's real content, so it is pure
   paint with no effect on .dock's own layout box or its sticky math. */
.dock[b-bhiodez556]::before {
  content: "";
  position: absolute;
  z-index: -1;
  top: 0;
  bottom: -2rem;
  left: -1.5rem;
  right: -1.5rem;
  background: #3f3f46;
}

/* Floats just above the dock. An absolutely positioned child of a position: sticky element is
   anchored to that element, not the viewport, so this rides along with the dock's own sticky
   position for free — js/diagnose.js only ever toggles it with the hidden attribute, never
   moves it. Centered over the dock rather than pinned to a corner: it points at "the bottom of
   this conversation", not at any one control in it. */
.jump-to-bottom[b-bhiodez556] {
  position: absolute;
  /* Overrides .dock > * + * : being last in the DOM (so it does not push the compose box
     down by that same rule) would otherwise hand it a margin-top it does not want. */
  margin-top: 0;
  top: -3.5rem;
  left: 50%;
  transform: translateX(-50%);
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 50%;
  border: 1px solid #d1d5db;
  background: #fff;
  color: #374151;
  box-shadow: 0 2px 8px rgba(0, 0, 0, .15);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

.jump-to-bottom:hover[b-bhiodez556] {
  background: #f3f4f6;
}

.jump-to-bottom svg[b-bhiodez556] {
  width: 1.35rem;
  height: 1.35rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Stacked in source order inside .dock: the retry banner, proposal card, or working/offline
   status (themselves mutually exclusive with each other) directly above the compose box, which
   is always the last child and always present. */
.dock > * + *[b-bhiodez556] {
  margin-top: .5rem;
}

.muted[b-bhiodez556] { color: #6b7280; font-size: .875rem; }
.error[b-bhiodez556] { color: #b91c1c; }

/* The machine name, state and Disconnect. Pinned on screen over the shell's dark blue top bar
   (app.css, .shell-bar, z-index: 3 — this sits above it at z-index: 4) without actually being a
   child of it: position: fixed anchors to the viewport, so the element stays put in Diagnose's
   own DOM (see the comment where this markup lives) while only its on-screen position matches
   the bar. .muted's colour was tuned for a white background and reads as barely-there on navy,
   so these are separate rather than reused.

   left aligns this with .shell-content's own left edge (shell-nav's width, plus shell-content's
   own left padding — app.css) rather than the "baicon" brand or nav-toggle button next to it
   on screen, since the technician reads this as the heading for the panel below it. */
.bar-session[b-bhiodez556] {
  position: fixed;
  z-index: 4;
  left: calc(var(--nav-w) + 1.5rem);
  top: 0;
  height: 3rem;
  display: flex;
  align-items: center;
  gap: .75rem;
}

/* Collapsing the nav (app.css, html.nav-collapsed) moves the content panel's own left edge all
   the way to the bar's own padding — 1.5rem, matching shell-content's left padding exactly —
   but the bar's hamburger button and "baicon" brand are still sitting right there (collapsing
   the nav does not move them), so following the content edge exactly would overlap them. This
   trades exact alignment for clearing both with room to spare: past the .75rem bar padding, the
   2rem toggle button, its .5rem gap, "baicon" itself, and one more .5rem gap. */
html.nav-collapsed .bar-session[b-bhiodez556] {
  left: 9rem;
}

.bar-name[b-bhiodez556] { color: #fff; font-weight: 600; font-size: 1rem; }
/* A link now, to the machine page, and still reads as the bar's title rather than a link. */
a.bar-name[b-bhiodez556] { text-decoration: none; }
a.bar-name:hover[b-bhiodez556] { text-decoration: underline; }
.inv dd a[b-bhiodez556] { color: #2563eb; }
.bar-muted[b-bhiodez556] { color: rgba(255, 255, 255, .75); font-size: .8rem; }

.bar-cancel[b-bhiodez556] {
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  font-size: .8rem;
  color: rgba(255, 255, 255, .85);
  text-decoration: underline;
  cursor: pointer;
}

.bar-cancel:hover[b-bhiodez556] {
  color: #fff;
}

/* Explicit rather than inherited: in the dock (white background) inheriting the page's default
   near-black text worked by coincidence, but the same pill now also renders in the shell's top
   bar (.bar-session above), which sets white text for everything in it. Inherited white on top
   of these pale pill colours made both the label and the dots (.dots, app.css, currentColor)
   next to invisible there. */
.state[b-bhiodez556] { font-size: .75rem; padding: .15rem .5rem; border-radius: 999px; background: #e5e7eb; color: #1f2937; }
.state-proposalpending[b-bhiodez556] { background: #fef3c7; }
.state-dispatching[b-bhiodez556], .state-opening[b-bhiodez556] { background: #dbeafe; }
/* The model actually thinking, dots and all, gets its own colour rather than sharing the blue
   used for "something on the wire is in flight" — it is the state worth a technician's eye
   the most, so it is the one that stands out. */
.state-awaitingmodel[b-bhiodez556] { background: #bbf7d0; }
.state-stopping[b-bhiodez556] { background: #e5e7eb; color: #4b5563; }
/* The only state pill that is a warning colour: it is the only one the technician cannot
   act their way out of. */
.state-workerlost[b-bhiodez556] { background: #fed7aa; color: #7c2d12; }

.workers[b-bhiodez556] { list-style: none; padding: 0; }
.workers li[b-bhiodez556] { display: flex; align-items: center; gap: .75rem; padding: .5rem 0; border-bottom: 1px solid #e5e7eb; }

/* The trailing padding is scroll room, not whitespace. Auto-scroll parks the newest entry clear
   of the dock, and a container with nothing below its last entry cannot scroll that extra
   distance — the browser stops at the end of the range and the entry stays where it was.

   Sized to the dock rather than fixed at 9rem, and that is what lets the scroll go all the way
   down. The room below the last entry and the height of the thing it has to clear were two
   independent numbers, so the end of the scroll range and the place the entry wanted to sit
   were never the same point: the scroll stopped at the entry with travel still left over, and
   the scrollbar never reached the end. Now the range ends exactly where the entry lands, so
   "scroll to the bottom" and "park the entry above the dock" are one instruction.

   The 14px matches DOCK_CLEARANCE_PX in js/diagnose.js: the dock's box-shadow paints about ten
   pixels above its own box, and a translucent shadow over the last line reads as a rendering
   fault rather than as a scroll that stopped short. The fallback covers the first paint, before
   js/diagnose.js has measured the dock. */
/* Reaching into SessionTranscript, deliberately. Both of these depend on --dock-h, which
   js/diagnose.js publishes from the dock's measured height, and the dock is this page's. The
   component ships neither, so the historical connection view -- no dock, no script -- does not
   inherit twelve rems of dead air under a finished transcript. */
/* On .chat-flow (transcript + inline actions) rather than on .transcript itself, so the
   inline proposal/working row sits right under the last message with the scroll room below
   it, not a dock's height of air between the two. */
.chat-flow[b-bhiodez556] {
  padding-bottom: calc(var(--dock-h, 12rem) + 14px);
}

/* Retry, proposal, working/offline status: inline under the last message, on the page's own
   light background (they used to live in the dark dock). */
.inline-actions > *[b-bhiodez556] {
  margin-top: .5rem;
}

/* How far above the bottom of the scroll container an entry has to land when it is scrolled
   into view. js/diagnose.js publishes --dock-h on the container and calls scrollIntoView; the
   browser does the rest, which is the point — it already knows about the sticky dock, the
   container and the end of the scroll range, and none of those were things arithmetic in the
   JS got reliably right.

   The extra 1rem is for what the dock paints outside its own box: box-shadow 0 -2px 8px
   reaches about ten pixels above it, and a translucent shadow over the last line reads as a
   rendering fault rather than as a scroll that stopped short. */
[b-bhiodez556] .entry {
  scroll-margin-bottom: calc(var(--dock-h, 0px) + 1rem);
}

.proposal[b-bhiodez556] { border: 2px solid #f59e0b; border-radius: .5rem; padding: 1rem; background: #fffbeb; }
.proposal-head[b-bhiodez556] { display: flex; align-items: baseline; gap: .5rem; }

/* Reset to plain bold text with just a click cue — same "looks like a label, works like a
   button" treatment as .who-toggle (now in SessionTranscript.razor.css), sized for the
   proposal head's inline flow instead of the
   transcript's small-caps "who" line. */
.proposal-name-toggle[b-bhiodez556] {
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  font-weight: 700;
  cursor: pointer;
  text-decoration: underline dotted;
  text-underline-offset: .15em;
}

.proposal-name-toggle:hover[b-bhiodez556] {
  color: #2563eb;
}

.why[b-bhiodez556] { margin: .5rem 0; }
.tier[b-bhiodez556] { font-size: .75rem; padding: .1rem .4rem; border-radius: .25rem; background: #e5e7eb; }
.tier-sensitiveread[b-bhiodez556] { background: #fde68a; }
/* Not a tier — it sits next to one, and says why this card exists even though the tier next to
   it is armed. Outlined rather than filled so it reads as a note on the tier beside it rather
   than a second, competing tier of its own. */
.tier-manual[b-bhiodez556] {
  background: none;
  border: 1px solid #9ca3af;
  color: #4b5563;
  cursor: help;
}
/* Not scoped to .proposal any more: the transcript's own "Tool - Suggested" entry shows this
   same parameter list, collapsed behind its heading, outside the dock's proposal card. */
dl[b-bhiodez556] { display: grid; grid-template-columns: auto 1fr; gap: .25rem .75rem; margin: .5rem 0; }
dt[b-bhiodez556] { font-weight: 600; font-size: .875rem; }
dd[b-bhiodez556] { margin: 0; font-family: ui-monospace, monospace; font-size: .875rem; }

/* Buttons on the left in a column, the note box filling the rest. Approve above Reject so the
   safer action is the one under the cursor coming down from the parameters above. */
.actions[b-bhiodez556] {
  display: flex;
  gap: .75rem;
  align-items: stretch;
  margin-top: .75rem;
}

.action-buttons[b-bhiodez556] {
  display: flex;
  flex-direction: column;
  gap: .4rem;
  flex: 0 0 auto;
}

/* Smaller all around now, not just shorter: less horizontal padding and a smaller font on top
   of the shorter height, since the parameter list under it collapses by default and no longer
   needs these to anchor a taller card. Width still 100% so Approve and Reject stay the same
   size as each other. */
.action-buttons button[b-bhiodez556] {
  width: 100%;
  padding: .15rem .6rem;
  font-size: .8rem;
}

/* Matches the two-button-plus-gap column height above it exactly, so the note box does not
   stick out past Approve/Reject or leave a gap under them. */
.actions .note[b-bhiodez556] {
  flex: 1;
  min-width: 0;
  height: 3.4rem;
  padding: .4rem;
  font: inherit;
  resize: vertical;
}
button[b-bhiodez556] { padding: .4rem .9rem; cursor: pointer; }
.approve[b-bhiodez556] { background: #059669; color: #fff; border: none; border-radius: .25rem; }
.reject[b-bhiodez556] { background: #dc2626; color: #fff; border: none; border-radius: .25rem; }

.compose[b-bhiodez556] { display: flex; gap: .5rem; align-items: center; }

/* Same fixed height as the Send button next to it (both set explicitly below, rather than left
   to match by coincidence of padding and font metrics), at rest. A background a shade off white
   marks it as "always here" even while it is plain white would read as a normal, ready field
   whether or not it actually is one right now. */
.compose textarea[b-bhiodez556] {
  flex: 1;
  height: 3.2rem;
  min-height: 3.2rem;
  /* js/diagnose.js reads this min/max back via getComputedStyle to grow the box as the
     technician types past two lines, so it stays the one place these numbers live. */
  max-height: 7.6rem;
  padding: .15rem .5rem;
  background: #eef1f5;
  border: 1px solid #cbd5e1;
  border-radius: .25rem;
  font: inherit;
  /* 75% of the previous 1.5rem. height/min-height/max-height above are scaled to match, so
     two lines still fit at rest and five lines still fit at the temporary max. */
  font-size: 1.125rem;
  line-height: 1.3;
  resize: none;
  overflow-y: auto;
}

/* Same explicit height as the textarea's resting height, so the two match exactly rather than
   approximately — button padding and line-height alone would only ever land close. */
.compose button[b-bhiodez556] {
  height: 3.2rem;
  padding: 0 .9rem;
  display: inline-flex;
  align-items: center;
}

/* Drafting: the turn is not the technician's, so what they type cannot be sent yet.

   Same size and background either way, because the size changing would be the exact reflow
   this box exists to avoid. Unlike the old :disabled rule this leaves the cursor and the text
   colour alone — the box really does accept typing now, and greying the text out or showing
   not-allowed would say the opposite of what is true. The muted left border is the whole
   signal, and the placeholder carries the rest. */
.compose textarea.drafting[b-bhiodez556] {
  border-left: 3px solid #cbd5e1;
}

.compose textarea:focus[b-bhiodez556] {
  outline: 2px solid #93c5fd;
  outline-offset: -1px;
}

/* Padding and font sizes here are about half of what they were: same reasoning as the smaller
   Approve/Reject buttons elsewhere in the dock (.action-buttons button) — this banner does not
   need to be this tall to be read. */
.retry[b-bhiodez556] {
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: .35rem 1rem;
  margin: .5rem 0;
  border: 1px solid #fca5a5;
  border-radius: .5rem;
  background: #fef2f2;
}
.retry span[b-bhiodez556] { color: #991b1b; font-size: .8rem; }
.retry button[b-bhiodez556] {
  background: #b91c1c;
  color: #fff;
  border: none;
  border-radius: .25rem;
  padding: .15rem .6rem;
  font-size: .8rem;
}

.working-row[b-bhiodez556] { display: flex; align-items: center; gap: .75rem; }

/* .dock's background is now dark; the default .muted grey is too low-contrast on it. Scoped
   to .working-row only — .proposal's own .muted sits on its own light background and needs
   to keep the original, darker grey. */
/* (Was #d1d5db for the dark dock; the row is inline on the light page now, so plain .muted.) */
.stop[b-bhiodez556] {
  background: #4b5563;
  color: #fff;
  border: none;
  border-radius: .25rem;
  padding: .25rem .75rem;
  font-size: .8rem;
}

/* The worker went away. Not an error the technician caused and not an ending, so it reads as
   a notice rather than a failure: amber, not red. */
.lost[b-bhiodez556] {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .5rem;
  padding: .75rem 1rem;
  border: 1px solid #fcd34d;
  border-left: 4px solid #f59e0b;
  border-radius: .25rem;
  background: #fffbeb;
}
.lost span[b-bhiodez556] { font-size: .875rem; }

/* Ending a session is not undoable, so it reads as an action rather than a link, and the
   confirm step is what stops a mis-click from throwing away a diagnosis. */
.disconnect[b-bhiodez556] {
  /* Brand orange rather than red, and the lighter tint of it rather than full strength: this
     is a filled button sitting in the dock next to the compose box, and the logo colour at full
     saturation pulls the eye there ahead of everything a technician is actually reading.

     Dark text, not white. White on either orange is around 3:1, under the 4.5:1 minimum for
     text this size; #3d2200 is 6.2:1 here. The Connection button's In Session state already
     pairs a warm background with dark text, so this is the shape the app already uses rather
     than a new one.

     Hover goes to the full-strength logo orange, which is the same colour the session list's
     attention dot uses -- one step darker, still the same hue. */
  background: var(--brand-orange-light);
  color: #3d2200;
  border: none;
  border-radius: .25rem;
  padding: .25rem .75rem;
  font-size: .8rem;
  cursor: pointer;
}

.disconnect:hover[b-bhiodez556] {
  background: var(--brand-orange);
}

/* The right panel. Two columns so labels and values line up down the edge, which is what makes
   a spec sheet scannable rather than a list of sentences. */
.inv[b-bhiodez556] {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: .3rem .75rem;
  margin: 0 0 .75rem;
  font-size: .85rem;
}

.inv dt[b-bhiodez556] {
  color: #6b7280;
  white-space: nowrap;
}

/* font-family and font-size are here to undo this file's own bare dt/dd rules, which the
   proposal's parameter list needs (monospace values, bold labels) and this panel does not.
   Those rules were written for the dock and reach the Machine section only because both are
   in Diagnose's scope. The Model section next to it lives in its own component, never saw
   them, and is what these two rows are matched to: same .85rem, same proportional face. */
.inv dd[b-bhiodez556] {
  margin: 0;
  overflow-wrap: anywhere;
  font-family: inherit;
  font-size: inherit;
}

.inv-when[b-bhiodez556] {
  margin: 0 0 .75rem;
}

.inv-json summary[b-bhiodez556] {
  cursor: pointer;
  font-size: .8rem;
  color: #2563eb;
}

.inv-json pre[b-bhiodez556] {
  margin: .5rem 0 0;
  padding: .5rem;
  background: #f9fafb;
  border: 1px solid #e5e7eb;
  border-radius: .25rem;
  font-size: .75rem;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  max-height: 28rem;
  overflow-y: auto;
}

.panel-title[b-bhiodez556] {
  margin: 0 0 .75rem;
  font-size: .95rem;
  font-weight: 600;
}

/* Shared by the Machine and Technician Settings sections in the right panel: each whole
   section collapses (<details>), not just Inventory JSON within it, so a technician can tuck
   either one away once they've read/set it rather than scrolling past it every time.
   The top border/gap is on the adjacent-sibling pair, not the base class, so Machine (which
   comes right after .customer's own bottom border) doesn't grow a second border of its own —
   only a .panel-section that follows another one, like Technician Settings after Machine,
   gets the separator. */
.panel-section summary[b-bhiodez556] {
  cursor: pointer;
}

.panel-section > p[b-bhiodez556] {
  margin: 0 0 .75rem;
}

.panel-section + .panel-section[b-bhiodez556] {
  margin-top: 1.1rem;
  padding-top: .9rem;
  border-top: 1px solid #e5e7eb;
}

.toggle-row[b-bhiodez556] {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
  padding: .35rem 0;
  font-size: .85rem;
  cursor: pointer;
}

.toggle-row input[b-bhiodez556] {
  cursor: pointer;
}

/* Who the machine belongs to, above the machine itself. A block of small lines with one
   larger name at the top, which is how an address reads on paper. */
.customer[b-bhiodez556] {
  margin: 0 0 1.1rem;
  padding: 0 0 .9rem;
  border-bottom: 1px solid #e5e7eb;
  font-size: .85rem;
  line-height: 1.45;
}

.customer div[b-bhiodez556] {
  overflow-wrap: anywhere;
}

.customer-name[b-bhiodez556] {
  margin: 0 0 .2rem;
  font-size: 1.05rem;
  font-weight: 600;
  line-height: 1.3;
}

.customer-name a[b-bhiodez556] {
  color: inherit;
  text-decoration: none;
}

.customer-name a:hover[b-bhiodez556] {
  text-decoration: underline;
}

/* The person at the desk, when that is not the same as the account. Set apart from the address
   below it so the two are not read as one block. */
.contact[b-bhiodez556] {
  margin-bottom: .35rem;
  color: #374151;
}

.contact a[b-bhiodez556] {
  color: #2563eb;
}

/* Small, under the name, and clearly secondary to it: this is a thing you do occasionally,
   not a thing you read. */
.reassign[b-bhiodez556] {
  display: inline-block;
  margin: 0 0 .4rem;
  font-size: .75rem;
  color: #2563eb;
}

/* Date and time at the bottom left of each stripe. 24-hour, two-digit hour. */

/* Ownership strip, top of the dock (Technician Work Page v1, section 5). Light text on the
   dock's dark background, same as .working-row. */
.ownership[b-bhiodez556] {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .5rem .75rem;
  color: #f3f4f6;
  font-size: .85rem;
  margin-bottom: .5rem;
}
.ownership .muted[b-bhiodez556] { color: #d1d5db; }
.ownership a[b-bhiodez556] { color: #93c5fd; }
.ownership .owner-line[b-bhiodez556] { margin-right: auto; }
.ownership .own-ask[b-bhiodez556] {
  background: #fef3c7;
  color: #78350f;
  border-radius: .25rem;
  padding: .15rem .5rem;
}
.ownership button[b-bhiodez556] {
  border: none;
  border-radius: .25rem;
  padding: .2rem .7rem;
  font-size: .8rem;
  cursor: pointer;
  color: #fff;
  background: #4b5563;
}
.ownership button:disabled[b-bhiodez556] { opacity: .5; cursor: default; }
.ownership .own-claim[b-bhiodez556],
.ownership .own-approve[b-bhiodez556] { background: #15803d; }
.ownership .own-deny[b-bhiodez556] { background: #b91c1c; }
.ownership .own-request[b-bhiodez556] { background: #2563eb; }
.ownership .own-takeover[b-bhiodez556] { background: #7c3aed; }

.stop:disabled[b-bhiodez556],
.disconnect:disabled[b-bhiodez556] { opacity: .5; cursor: default; }

/* Same inline-code look as tool names in the transcript (SessionTranscript.razor.css). */
.tool-name[b-bhiodez556] {
  background: #e5e7eb;
  border-radius: .2rem;
  padding: .05rem .35rem;
  font-size: .85em;
}

/* Machine Notes in the right panel. Technician free text, so wrap anything. */
.notes[b-bhiodez556] {
  margin: 0 0 .5rem;
  padding-left: 1.1rem;
  font-size: .85rem;
}

.notes li[b-bhiodez556] {
  margin: .25rem 0;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.notes-edit[b-bhiodez556] {
  font-size: .85rem;
}

.notes-section > p.notes-hint[b-bhiodez556] {
  margin: .25rem 0 0;
  font-size: .75rem;
}

/* Notes, nested inside the Machine section with its own toggle. */
.notes-section[b-bhiodez556] {
  margin-top: .75rem;
  padding-top: .6rem;
  border-top: 1px solid #f3f4f6;
}

.notes-title[b-bhiodez556] {
  cursor: pointer;
  font-size: .85rem;
  font-weight: 600;
  margin-bottom: .4rem;
}

.notes-section > p[b-bhiodez556] {
  margin: 0 0 .5rem;
}
/* /Components/Pages/Settings/ModelEndpoints.razor.rz.scp.css */
/* Saved model endpoints, above the Model Endpoint settings table. Set apart with a light box so
   it reads as "presets for the rows below" rather than as more rows. */
.endpoints[b-8hslhmzr4j] {
    margin: 0 0 1rem;
    padding: .75rem 1rem;
    border: 1px solid #e5e7eb;
    border-radius: .375rem;
    background: #f9fafb;
    max-width: 48rem;
}

.ep-pick[b-8hslhmzr4j] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .5rem .75rem;
    margin-bottom: .75rem;
}

.ep-pick label[b-8hslhmzr4j] {
    font-weight: 600;
}

.ep-status[b-8hslhmzr4j] {
    font-size: .9rem;
    color: #374151;
}

.ep-warn[b-8hslhmzr4j] {
    color: #b45309;
}

.ep-form[b-8hslhmzr4j] {
    width: 100%;
    border-collapse: collapse;
}

.ep-form td[b-8hslhmzr4j] {
    padding: .25rem .5rem .25rem 0;
    vertical-align: middle;
}

.ep-key[b-8hslhmzr4j] {
    width: 12rem;
    font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
    font-size: .85rem;
    white-space: nowrap;
}

.ep-form .setting-input[b-8hslhmzr4j] {
    width: 100%;
    box-sizing: border-box;
}

.ep-actions[b-8hslhmzr4j] {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    margin-top: .75rem;
}
/* /Components/Pages/Settings/SystemPrompts.razor.rz.scp.css */
.prompt-edit[b-yqm09lobib] {
  max-width: 64rem;
}

.prompt-edit label[b-yqm09lobib] {
  display: block;
  margin-top: 1rem;
  font-weight: 600;
}

.prompt-edit label .muted[b-yqm09lobib] {
  font-weight: normal;
  font-size: .85rem;
  margin-left: .5rem;
}

.prompt-edit textarea[b-yqm09lobib],
.prompt-edit input[b-yqm09lobib] {
  display: block;
  width: 100%;
  margin-top: .3rem;
  padding: .45rem;
  border: 1px solid #ced4da;
  border-radius: .25rem;
  font-weight: normal;
}

.prompt-edit textarea[b-yqm09lobib] {
  font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
  font-size: .85rem;
  resize: vertical;
}

.prompt-actions[b-yqm09lobib] {
  display: flex;
  align-items: center;
  gap: .6rem;
  margin: 1rem 0 1.5rem;
}

.prompt-actions button[b-yqm09lobib],
.versions button[b-yqm09lobib] {
  padding: .4rem .9rem;
  border: 1px solid #ced4da;
  border-radius: .25rem;
  background: #fff;
  cursor: pointer;
}

.prompt-actions button.primary[b-yqm09lobib],
.versions button.primary[b-yqm09lobib] {
  border-color: #1b6ec2;
  background: #1b6ec2;
  color: #fff;
}

.prompt-actions button:disabled[b-yqm09lobib],
.versions button:disabled[b-yqm09lobib] {
  opacity: .5;
  cursor: default;
}

.versions[b-yqm09lobib] {
  border-collapse: collapse;
  width: 100%;
  max-width: 64rem;
  font-size: .875rem;
}

.versions th[b-yqm09lobib],
.versions td[b-yqm09lobib] {
  border-bottom: 1px solid #e5e7eb;
  padding: .4rem .6rem;
  text-align: left;
  vertical-align: top;
}

.versions tr.active td[b-yqm09lobib] {
  background: #f0f7ff;
}

.notes-cell[b-yqm09lobib] {
  overflow-wrap: anywhere;
}

.notes-cell summary[b-yqm09lobib] {
  cursor: pointer;
  color: #2563eb;
  font-size: .8rem;
  margin-top: .25rem;
}

.notes-cell pre[b-yqm09lobib] {
  white-space: pre-wrap;
  background: #f9fafb;
  border: 1px solid #e5e7eb;
  padding: .5rem;
  max-height: 24rem;
  overflow-y: auto;
  font-size: .75rem;
}

.raw-label[b-yqm09lobib] {
  display: block;
  font-size: .75rem;
  font-weight: 600;
  margin-top: .5rem;
  color: #6b7280;
}

.muted[b-yqm09lobib] {
  color: #6b7280;
}

.notice[b-yqm09lobib] {
  padding: .6rem .75rem;
  border-radius: .25rem;
}

.notice-ok[b-yqm09lobib] {
  background-color: #d1e7dd;
  color: #0f5132;
}

.notice-error[b-yqm09lobib] {
  background-color: #f8d7da;
  color: #842029;
}

.by[b-yqm09lobib] {
  font-size: .75rem;
  color: #6b7280;
}

.versions .actions-cell[b-yqm09lobib] {
  width: 1%;
  white-space: nowrap;
}

.row-actions[b-yqm09lobib] {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: .4rem;
  min-width: 7.5rem;
}

.row-actions strong[b-yqm09lobib] {
  text-align: center;
  padding: .4rem 0;
}

.versions .confirm[b-yqm09lobib] {
  font-size: .8rem;
  text-align: center;
}

.versions button.danger[b-yqm09lobib] {
  border-color: #b02a37;
  background: #b02a37;
  color: #fff;
}
/* /Components/Sessions/SessionTranscript.razor.rz.scp.css */
/* The transcript's own styles, scoped to this component.

   Blazor's CSS isolation stamps its scope attribute onto elements written in a component's
   markup at compile time, so these rules follow the markup here rather than staying behind in
   Diagnose.razor.css. Everything written here is written as markup in the .razor file for the
   same reason: an element built any other way does not carry the attribute and does not match
   (pre.why is the one that bit, rendering as a single enormously wide line).

   Two things deliberately NOT here:

   1. The transcript's bottom clearance and .entry's scroll-margin-bottom. Both depend on
      --dock-h, which js/diagnose.js publishes from the dock's measured height. This component
      has no dock and the historical page has no script, so the fallback would leave twelve rems
      of dead air under a finished transcript. Diagnose adds them back through ::deep, because
      the dock's geometry belongs to the page that has a dock.

   2. Nothing about the proposal card, the compose box or the state pills. Those are the live
      page's and never render here.

   .muted, .error, .why and dl are duplicated in Diagnose.razor.css on purpose. They are used by
   the transcript and by the dock, and scoped CSS cannot be shared: the alternative is this
   component reaching for styles it does not own, which is the coupling isolation exists to
   prevent. Keep the copies identical and short. */

.transcript[b-yei84pz4i0] {
  margin: 1rem 0;
}

.entry[b-yei84pz4i0] { padding: .5rem 0; border-bottom: 1px solid #f3f4f6; }
/* pre-wrap rather than injecting <br> tags: the model's own paragraph breaks and blank lines
   come through exactly as it wrote them, with no need to trust or sanitise markup. */
.entry p[b-yei84pz4i0] { margin: .25rem 0; white-space: pre-wrap; }
.who[b-yei84pz4i0] { font-size: .75rem; text-transform: uppercase; letter-spacing: .04em; color: #6b7280; }
.entry pre[b-yei84pz4i0] { background: #f9fafb; padding: .5rem; overflow-x: auto; font-size: .8rem; max-height: 18rem; }

/* Every transcript entry zebra-stripes against the one before it — every entry has its own
   border-bottom (.entry above), so every one of those lines is a stripe boundary. Negative
   margin plus matching padding so the stripe reads as a full-width band without shifting where
   the text itself starts. */
.entry-alt[b-yei84pz4i0] {
  /* Twice as far from white as before (#f9fafb was 4-6 off white; this is 8-12 off), so the
     stripe reads clearly at a glance instead of needing a second look. */
  background: #f3f5f7;
  margin-left: -.75rem;
  margin-right: -.75rem;
  padding-left: .75rem;
  padding-right: .75rem;
  border-radius: .25rem;
}

/* A tool result and the proposal it answers are one section. The proposal keeps the stripe and
   drops the rule and the gap below it; the result picks up where it left off. Written as two
   classes on two elements rather than one wrapper because the render loop emits one .entry per
   transcript entry, and the pair is a display fact, not a transcript one. */
.entry-open[b-yei84pz4i0] {
  border-bottom: none;
  padding-bottom: 0;
}

.entry-cont[b-yei84pz4i0] {
  padding-top: 0;
}

/* The stripe's rounding belongs to the band, not to each half of it, or a corner turns up in
   the middle of the pair. */
.entry-alt.entry-open[b-yei84pz4i0] {
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
}

.entry-alt.entry-cont[b-yei84pz4i0] {
  border-top-left-radius: 0;
  border-top-right-radius: 0;
}

/* Reset the button chrome so a clickable tool name reads exactly like .who used to as plain
   text; the underline is the only added cue that it does something. */
.who-toggle[b-yei84pz4i0] {
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  font-size: .75rem;
  text-transform: uppercase;
  letter-spacing: .04em;
  cursor: pointer;
  text-decoration: underline dotted;
  text-underline-offset: .15em;
}

.who-toggle:hover[b-yei84pz4i0] {
  color: #2563eb;
}

/* No .status/.status-* rules: the coloured "Success"/"Rejected"/... badge is gone. The
   heading itself ("Tool - Executed", "Tool - Rejected", "Tool - Failed") already says the
   status, on its own line, with nothing crowded onto it. */

pre.why[b-yei84pz4i0] {
  /* pre-wrap keeps the model's own line breaks and wraps everything else. overflow-wrap
     handles the case pre-wrap cannot: a single token longer than the column, which a file
     path or a stack frame routinely is. */
  white-space: pre-wrap;
  overflow-wrap: anywhere;

  background: #f9fafb;
  border-left: 3px solid #d1d5db;
  padding: .5rem .75rem;
  margin: 0 0 .6rem;
  font-size: .8rem;
  line-height: 1.45;
  /* Half of the old 20rem: collapsed by default now (the why-toggle above it), so the case
     this height is for — an exceptionally long block someone chose to expand — needs less
     room reserved than when every reasoning block rendered open. */
  max-height: 10rem;
  overflow-y: auto;
  color: #374151;
}

/* Captions over the Assistant heading's two blocks, shown only when both are there. Same
   treatment as .who, a shade lighter, so they read as sub-headings under it rather than as
   two more speakers. */
.raw-label[b-yei84pz4i0] {
  display: block;
  font-size: .7rem;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: #9ca3af;
  margin: 0 0 .2rem;
}

.entry-time[b-yei84pz4i0] { display: block; text-align: left; margin-top: .25rem; font-size: .65rem; color: #000; font-variant-numeric: tabular-nums; }

/* --- shared with Diagnose.razor.css; keep the copies identical ------------- */
.muted[b-yei84pz4i0] { color: #6b7280; font-size: .875rem; }
.error[b-yei84pz4i0] { color: #b91c1c; }
.why[b-yei84pz4i0] { margin: .5rem 0; }
dl[b-yei84pz4i0] { display: grid; grid-template-columns: auto 1fr; gap: .25rem .75rem; margin: .5rem 0; }

/* Tool names render like markdown `inline code` — same look as RichText's .rt-code. */
.tool-name[b-yei84pz4i0] {
  background: #e5e7eb;
  border-radius: .2rem;
  padding: .05rem .35rem;
  font-size: .85em;
  font-weight: 600;
}
