/* /Components/Controls/BarChart.razor.rz.scp.css */
/* BarChart: the Dashboard's time to resolution. Colors are theme variables (themes.css). */
.bars[b-ltxvpr7ppy] {
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: .5rem;
}

.bars-title[b-ltxvpr7ppy] {
    font-weight: 600;
}

.bars-svg[b-ltxvpr7ppy] {
    width: 100%;
    height: auto;
    display: block;
}

.bars-grid[b-ltxvpr7ppy] {
    stroke: var(--yf-border);
    stroke-width: 1;
}

.bars-axis[b-ltxvpr7ppy] {
    fill: var(--yf-muted);
    font-size: 10px;
}

/* The whole column answers the hover, not just the bar. */
.bars-hit[b-ltxvpr7ppy] {
    fill: transparent;
}

.bars-col:hover .bars-hit[b-ltxvpr7ppy] {
    fill: var(--yf-border);
    opacity: .35;
}

.bars-bar[b-ltxvpr7ppy] {
    transition: opacity .15s ease;
}

.bars-col:hover .bars-bar[b-ltxvpr7ppy] {
    opacity: .85;
}

.bars-empty[b-ltxvpr7ppy] {
    margin: 0;
}
/* /Components/Controls/ConfirmButton.razor.rz.scp.css */
/* The small red button every quick Delete and Abort uses, and the confirmation popup it opens.
   The popup's keyframes live in wwwroot/app.css (confirm-*), with the other global animations. */

.confirm-danger[b-phrxrojmjc] {
    padding: .1rem .55rem;
    font-size: .85rem;
    line-height: 1.4;
    border: 1px solid var(--yf-danger);
    border-radius: .25rem;
    background-color: var(--yf-danger);
    color: var(--yf-on-color);
    cursor: pointer;
    white-space: nowrap;
}

.confirm-danger:hover:not(:disabled)[b-phrxrojmjc] {
    background-color: var(--yf-danger);
    border-color: var(--yf-danger);
}

.confirm-danger:disabled[b-phrxrojmjc] {
    opacity: .5;
    cursor: default;
}

/* The native <dialog> the popup lives in (top layer, see ConfirmButton.razor): a transparent box
   the size of the screen, with the browser's own ::backdrop switched off in favour of ours. */
.confirm-host[b-phrxrojmjc] {
    position: fixed;
    inset: 0;
    width: 100%;
    height: 100%;
    max-width: none;
    max-height: none;
    margin: 0;
    padding: 0;
    border: 0;
    background: transparent;
    overflow: visible;
    color: inherit;
}

.confirm-host[b-phrxrojmjc]::backdrop {
    background: transparent;
}

/* Fixed to the viewport, so it opens in the middle of the screen even from inside a table row. */
.confirm-backdrop[b-phrxrojmjc] {
    position: fixed;
    inset: 0;
    z-index: 2000;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1rem;
    background-color: var(--yf-shadow);
    animation: confirm-fade-in .16s ease-out both;
    white-space: normal;
    text-align: left;
    cursor: default;
}

.confirm-dialog[b-phrxrojmjc] {
    width: 100%;
    max-width: 26rem;
    padding: 1.5rem 1.5rem 1.25rem;
    border-radius: .6rem;
    background-color: var(--bs-body-bg);
    color: var(--bs-body-color);
    box-shadow: 0 20px 45px var(--yf-shadow), 0 4px 12px var(--yf-shadow);
    text-align: center;
    animation: confirm-pop-in .22s cubic-bezier(.2, .9, .3, 1.25) both;
}

/* Focusable only so the D and Escape keys keep working after a click on its text. */
.confirm-dialog:focus[b-phrxrojmjc] {
    outline: none;
}

.confirm-icon[b-phrxrojmjc] {
    width: 2.75rem;
    height: 2.75rem;
    margin: 0 auto .75rem;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: var(--bs-body-bg);
    color: var(--yf-danger-fg);
    font-size: 1.5rem;
    font-weight: 700;
    line-height: 1;
    animation: confirm-icon-pulse .5s ease-out .15s both;
}

.confirm-heading[b-phrxrojmjc] {
    margin: 0 0 .5rem;
    font-size: 1.15rem;
    font-weight: 600;
    line-height: 1.3;
}

.confirm-message[b-phrxrojmjc] {
    /* Keeps the line breaks a Message carries: callers put a blank line before
       "There is no undo." so it stands on its own (owner, 2026-10-07). */
    white-space: pre-line;
    margin: 0 0 .25rem;
    font-size: .92rem;
    line-height: 1.45;
    color: var(--yf-muted);
}

/* A caller's extra controls under the message (End Connection's follow-up checkbox). */
.confirm-extra[b-phrxrojmjc] {
    display: flex;
    justify-content: center;
    margin: .75rem 0 .25rem;
}

.confirm-actions[b-phrxrojmjc] {
    display: flex;
    justify-content: center;
    gap: .6rem;
    margin-top: 1.25rem;
}

.confirm-cancel[b-phrxrojmjc],
.confirm-go[b-phrxrojmjc] {
    min-width: 7rem;
    padding: .45rem 1rem;
    font-size: .92rem;
    line-height: 1.3;
    border-radius: .3rem;
    cursor: pointer;
    margin: 0;
}

.confirm-cancel[b-phrxrojmjc] {
    border: 1px solid var(--yf-border);
    background-color: var(--bs-body-bg);
    color: var(--bs-body-color);
}

.confirm-cancel:hover[b-phrxrojmjc] {
    background-color: var(--bs-body-bg);
}

.confirm-go[b-phrxrojmjc] {
    border: 1px solid var(--yf-danger);
    background-color: var(--yf-danger);
    color: var(--yf-on-color);
}

/* The D shortcut, barely there: a faint keycap after the label. */
.confirm-key[b-phrxrojmjc] {
    display: inline-block;
    margin-left: .55rem;
    padding: 0 .3rem;
    border: 1px solid var(--yf-on-color-soft);
    border-radius: .2rem;
    font-size: .68rem;
    line-height: 1.35;
    font-weight: 600;
    vertical-align: .08em;
    opacity: .55;
}

.confirm-go:hover:not(:disabled)[b-phrxrojmjc] {
    background-color: var(--yf-danger);
    border-color: var(--yf-danger);
}

.confirm-go:disabled[b-phrxrojmjc] {
    opacity: .5;
    cursor: default;
}

.confirm-cancel:focus-visible[b-phrxrojmjc],
.confirm-go:focus-visible[b-phrxrojmjc] {
    outline: 2px solid var(--brand-blue);
    outline-offset: 2px;
}

.confirm-closing[b-phrxrojmjc] {
    animation: confirm-fade-out .14s ease-in both;
}

.confirm-closing .confirm-dialog[b-phrxrojmjc] {
    animation: confirm-pop-out .14s ease-in both;
}

@media (prefers-reduced-motion: reduce) {
    .confirm-backdrop[b-phrxrojmjc],
    .confirm-dialog[b-phrxrojmjc],
    .confirm-icon[b-phrxrojmjc],
    .confirm-closing[b-phrxrojmjc],
    .confirm-closing .confirm-dialog[b-phrxrojmjc] {
        animation-duration: 1ms;
    }
}

/* Primary (Resolve on an open issue): brand blue and a check mark, for an action that is not
   destructive. The caller's controls (a note) stretch the width of the box. */
.confirm-primary .confirm-icon[b-phrxrojmjc] { color: var(--brand-blue); }
.confirm-primary .confirm-go[b-phrxrojmjc] {
    border-color: var(--brand-blue);
    background-color: var(--brand-blue);
    color: var(--yf-on-color);
}
.confirm-primary .confirm-go:disabled[b-phrxrojmjc] { opacity: .5; cursor: default; }
.confirm-primary .confirm-extra[b-phrxrojmjc] { display: block; text-align: left; }
/* /Components/Controls/DonutChart.razor.rz.scp.css */
/* DonutChart: the Dashboard's charts. Colors are theme variables (themes.css, Charts group). */
.donut[b-kyw6qu14vv] {
    margin: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: .75rem;
}

.donut-title[b-kyw6qu14vv] {
    align-self: stretch;
    font-weight: 600;
}

.donut-svg[b-kyw6qu14vv] {
    width: 11rem;
    height: 11rem;
    /* The ring starts at twelve o'clock and runs clockwise (stroke-dashoffset 25 in the markup). */
}

.donut-track[b-kyw6qu14vv] {
    fill: none;
    stroke: var(--yf-border);
    stroke-width: 5;
    opacity: .35;
}

.donut-slice[b-kyw6qu14vv] {
    fill: none;
    stroke-width: 5;
    transition: stroke-dasharray .3s ease, stroke-dashoffset .3s ease;
}

    .donut-slice:hover[b-kyw6qu14vv] {
        stroke-width: 6;
    }

.donut-total[b-kyw6qu14vv] {
    fill: var(--bs-body-color);
    font-size: 8px;
    font-weight: 600;
    text-anchor: middle;
}

.donut-unit[b-kyw6qu14vv] {
    fill: var(--yf-muted);
    font-size: 3px;
    text-anchor: middle;
}

.donut-legend[b-kyw6qu14vv] {
    list-style: none;
    margin: 0;
    padding: 0;
    align-self: stretch;
    font-size: .85rem;
}

    .donut-legend li[b-kyw6qu14vv] {
        display: flex;
        align-items: center;
        gap: .5rem;
        padding: .15rem 0;
    }

.donut-swatch[b-kyw6qu14vv] {
    width: .7rem;
    height: .7rem;
    border-radius: 3px;
    flex: none;
}

.donut-label[b-kyw6qu14vv] {
    overflow-wrap: anywhere;
}

.donut-value[b-kyw6qu14vv] {
    margin-left: auto;
    white-space: nowrap;
}

.donut-empty[b-kyw6qu14vv] {
    margin: 2rem 0;
}

@media (prefers-reduced-motion: reduce) {
    .donut-slice[b-kyw6qu14vv] { transition: none; }
}
/* /Components/Controls/FollowUpCheckbox.razor.rz.scp.css */
/* "Flag this machine for follow-up": a checkbox and its words, one line. */
.followup-check[b-dxettx4s07] {
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    margin: .5rem 0;
    font-size: .92rem;
    cursor: pointer;
}

    .followup-check input[b-dxettx4s07] {
        width: 1rem;
        height: 1rem;
        margin: 0;
    }
/* /Components/Issues/AddOpenIssue.razor.rz.scp.css */
/* Add open issue, on the machine page. */
.issue-add[b-503zge2gvz] {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    max-width: 40rem;
}

    .issue-add input[b-503zge2gvz] {
        flex: 1 1 16rem;
        min-width: 0;
        width: auto;
    }
/* /Components/Issues/OpenIssuesBadge.razor.rz.scp.css */
/* The open issue count in the left panel: a small pill at the end of the row, in the menu's own
   colors so it follows the scheme. */
.nav-badge[b-mkr6zaywul] {
    margin-left: auto;
    min-width: 1.25rem;
    height: 1.25rem;
    padding: 0 .4rem;
    border-radius: .625rem;
    background: var(--brand-orange);
    color: var(--yf-on-orange);
    font-size: .7rem;
    font-weight: 600;
    line-height: 1.25rem;
    text-align: center;
}
/* /Components/Issues/OpenIssueTable.razor.rz.scp.css */
/* Open issues table (Open Issues page and the machine page). */
.issue-date[b-bc9e7ht6kr] {
    white-space: nowrap;
}

.issue-headline[b-bc9e7ht6kr] {
    overflow-wrap: anywhere;
}

.issue-by[b-bc9e7ht6kr] {
    font-size: .75rem;
}

.issue-resolve-label[b-bc9e7ht6kr] {
    display: block;
    margin-bottom: .25rem;
    font-size: .85rem;
    font-weight: 600;
}

.issue-resolve-note[b-bc9e7ht6kr] {
    width: 100%;
    resize: vertical;
}
/* /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-fepfhnc0z3] {
  margin-top: 1.1rem;
  padding-top: .9rem;
  border-top: 1px solid var(--yf-border);
}

.panel-section summary[b-fepfhnc0z3] {
  cursor: pointer;
}

.panel-title[b-fepfhnc0z3] {
  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-fepfhnc0z3] {
  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-fepfhnc0z3] {
  color: var(--yf-muted);
  font-weight: 700;
}

.toggle-row input[b-fepfhnc0z3] {
  cursor: pointer;
}
/* /Components/Layout/LegalChangeBanner.razor.rz.scp.css */
.legal-banner[b-2as56jq811] {
    padding: .5rem 1rem;
    background: var(--bs-body-bg);
    border-bottom: 1px solid var(--yf-border);
    font-size: .92rem;
}

.legal-banner p[b-2as56jq811] {
    margin: .2rem 0;
}

.legal-banner a[b-2as56jq811] {
    margin-left: .35rem;
}
/* /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-ersbep5abr] {
    color-scheme: light only;
    background: var(--bs-body-bg);
    bottom: 0;
    box-shadow: 0 -1px 2px var(--yf-shadow);
    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-ersbep5abr] {
        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-qdut434635] {
  margin-top: 1.1rem;
  padding-top: .9rem;
  border-top: 1px solid var(--yf-border);
}

.panel-section summary[b-qdut434635] {
  cursor: pointer;
}

.panel-section > p[b-qdut434635] {
  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-qdut434635] {
  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-qdut434635] {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: .3rem .75rem;
  margin: 0 0 .75rem;
  font-size: .85rem;
}

.inv dt[b-qdut434635] {
  color: var(--yf-muted);
  white-space: nowrap;
}

.inv dd[b-qdut434635] {
  margin: 0;
  overflow-wrap: anywhere;
}

.inv-when[b-qdut434635] {
  margin: 0 0 .75rem;
}

.muted[b-qdut434635] {
  color: var(--yf-muted);
  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-qdut434635] {
  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-qdut434635] {
  font-size: .85rem;
  padding: .15rem .3rem;
  cursor: pointer;
}

/* The two penalty boxes: the select's type size, narrow because the value is at most "-1.25". */
.inv dd input[type="number"][b-qdut434635] {
  font-size: .85rem;
  padding: .15rem .3rem;
  width: 5.5rem;
}
/* /Components/Layout/NavMenu.razor.rz.scp.css */
/* The left panel (owner, 2026-10-11): grouped links, each with its own icon, in the menu's own
   colors (themes.css, Menu group), so the whole column follows the scheme. The burger and the
   brand live in the shell's top bar. */

/* One icon per link. Each is a mask, not a picture: the SVG only says where the paint goes, and
   background-color says what color, so an icon is always the menu's icon color (or the current
   page's) on Light, on Dark and under anything set on Server Settings > Appearance. The white
   SVG images these replace could not change with the scheme, and three links (Technicians, Shop
   Settings, Server Settings) named classes that were never defined, so they showed a blank.

   24 x 24 grid, 1.75 stroke, round caps and joins, drawn to match the marketing site's line
   icons. The same paths are on the design canvas (Left Panel Redesign, Icons). */
.nav-icon[b-1u7rzq3ewc] {
    display: inline-block;
    flex: none;
    width: 1.25rem;
    height: 1.25rem;
    margin-right: .75rem;
    background-color: var(--yf-menu-icon);
    -webkit-mask-position: center;
    mask-position: center;
    -webkit-mask-size: contain;
    mask-size: contain;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
}

/* Dashboard */
.icon-dashboard[b-1u7rzq3ewc] {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 5a1 1 0 0 1 1-1h5a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1z M13 5a1 1 0 0 1 1-1h5a1 1 0 0 1 1 1v3a1 1 0 0 1-1 1h-5a1 1 0 0 1-1-1z M13 13a1 1 0 0 1 1-1h5a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1h-5a1 1 0 0 1-1-1z M4 16a1 1 0 0 1 1-1h5a1 1 0 0 1 1 1v3a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1z'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 5a1 1 0 0 1 1-1h5a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1z M13 5a1 1 0 0 1 1-1h5a1 1 0 0 1 1 1v3a1 1 0 0 1-1 1h-5a1 1 0 0 1-1-1z M13 13a1 1 0 0 1 1-1h5a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1h-5a1 1 0 0 1-1-1z M4 16a1 1 0 0 1 1-1h5a1 1 0 0 1 1 1v3a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1z'/%3E%3C/svg%3E");
}

/* Open Issues: a flag */
.icon-issues[b-1u7rzq3ewc] {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 21V4 M5 4h11l-2 4 2 4H5'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 21V4 M5 4h11l-2 4 2 4H5'/%3E%3C/svg%3E");
}

/* Connections: a plug */
.icon-connections[b-1u7rzq3ewc] {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9 3v4 M15 3v4 M7 7h10v4a5 5 0 0 1-10 0z M12 16v5'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9 3v4 M15 3v4 M7 7h10v4a5 5 0 0 1-10 0z M12 16v5'/%3E%3C/svg%3E");
}

/* DailyDelta: a clipboard with a tick */
.icon-delta[b-1u7rzq3ewc] {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9 4h6a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H9a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1z M16 5h1a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V7a2 2 0 0 1 2-2h1 M9 14l2 2 4-4'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9 4h6a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H9a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1z M16 5h1a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V7a2 2 0 0 1 2-2h1 M9 14l2 2 4-4'/%3E%3C/svg%3E");
}

/* Customers: two people */
.icon-customers[b-1u7rzq3ewc] {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9 11a3.5 3.5 0 1 0 0-7 3.5 3.5 0 0 0 0 7z M3 20v-1a5 5 0 0 1 5-5h2a5 5 0 0 1 5 5v1 M16 4.3a3.5 3.5 0 0 1 0 6.4 M18 14.2a5 5 0 0 1 3 4.8v1'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9 11a3.5 3.5 0 1 0 0-7 3.5 3.5 0 0 0 0 7z M3 20v-1a5 5 0 0 1 5-5h2a5 5 0 0 1 5 5v1 M16 4.3a3.5 3.5 0 0 1 0 6.4 M18 14.2a5 5 0 0 1 3 4.8v1'/%3E%3C/svg%3E");
}

/* Machines: a monitor */
.icon-machines[b-1u7rzq3ewc] {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 5a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v10a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1z M9 20h6 M12 16v4'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 5a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v10a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1z M9 20h6 M12 16v4'/%3E%3C/svg%3E");
}

/* Installers: a download into a tray */
.icon-installers[b-1u7rzq3ewc] {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 4v11 M7.5 10.5 12 15l4.5-4.5 M5 17v2a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-2'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 4v11 M7.5 10.5 12 15l4.5-4.5 M5 17v2a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-2'/%3E%3C/svg%3E");
}

/* PCScan: a scan frame */
.icon-pcscan[b-1u7rzq3ewc] {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 8V6a2 2 0 0 1 2-2h2 M16 4h2a2 2 0 0 1 2 2v2 M20 16v2a2 2 0 0 1-2 2h-2 M8 20H6a2 2 0 0 1-2-2v-2 M7 12h10'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 8V6a2 2 0 0 1 2-2h2 M16 4h2a2 2 0 0 1 2 2v2 M20 16v2a2 2 0 0 1-2 2h-2 M8 20H6a2 2 0 0 1-2-2v-2 M7 12h10'/%3E%3C/svg%3E");
}

/* Technicians: an ID badge */
.icon-technicians[b-1u7rzq3ewc] {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 6a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2z M12 11.5a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5z M8.5 17a3.5 3.5 0 0 1 7 0'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 6a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2z M12 11.5a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5z M8.5 17a3.5 3.5 0 0 1 7 0'/%3E%3C/svg%3E");
}

/* Shop Settings: a shopfront */
.icon-shop[b-1u7rzq3ewc] {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 9l1.5-5h13L20 9 M4 9a2.67 2.67 0 0 0 5.33 0 2.67 2.67 0 0 0 5.34 0A2.67 2.67 0 0 0 20 9 M5 11.5V20h14v-8.5 M10 20v-5h4v5'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 9l1.5-5h13L20 9 M4 9a2.67 2.67 0 0 0 5.33 0 2.67 2.67 0 0 0 5.34 0A2.67 2.67 0 0 0 20 9 M5 11.5V20h14v-8.5 M10 20v-5h4v5'/%3E%3C/svg%3E");
}

/* Server Settings: two server units */
.icon-server[b-1u7rzq3ewc] {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v2a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2z M4 16a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v2a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2z M8 7h.01 M8 17h.01'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v2a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2z M4 16a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v2a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2z M8 7h.01 M8 17h.01'/%3E%3C/svg%3E");
}

/* Tutorial: an open book */
.icon-tutorial[b-1u7rzq3ewc] {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 7v12 M12 7C10.5 5.5 8 5 4 5v12c4 0 6.5.5 8 2 M12 7c1.5-1.5 4-2 8-2v12c-4 0-6.5.5-8 2'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 7v12 M12 7C10.5 5.5 8 5 4 5v12c4 0 6.5.5 8 2 M12 7c1.5-1.5 4-2 8-2v12c-4 0-6.5.5-8 2'/%3E%3C/svg%3E");
}

/* Feedback: a speech bubble */
.icon-feedback[b-1u7rzq3ewc] {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 5h14a1 1 0 0 1 1 1v9a1 1 0 0 1-1 1h-7l-4 4v-4H5a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1z'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 5h14a1 1 0 0 1 1 1v9a1 1 0 0 1-1 1h-7l-4 4v-4H5a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1z'/%3E%3C/svg%3E");
}

/* Leaves the app: an arrow out */
.icon-external[b-1u7rzq3ewc] {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 16 16 8 M10 8h6v6'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 16 16 8 M10 8h6v6'/%3E%3C/svg%3E");
}

/* "Leaves the app" on Feedback, which opens GitHub in a new tab: small, muted, at the row's end. */
.nav-external[b-1u7rzq3ewc] {
    width: .875rem;
    height: .875rem;
    margin: 0 0 0 auto;
    background-color: var(--yf-menu-muted);
}

/* A group's heading: Work, Customers, Your shop, Operator. Lined up with the icons. */
.nav-group[b-1u7rzq3ewc] {
    display: flex;
    align-items: baseline;
    gap: .375rem;
    padding: .875rem 1.625rem .25rem;
    font-size: .7rem;
    font-weight: 600;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--yf-menu-muted);
}

/* Tight rows (owner, 2026-10-05): 2rem links with a hair between them, rather than 3rem
   links half a rem apart. Still a comfortable click target. */
.nav-item[b-1u7rzq3ewc] {
    font-size: .9rem;
    padding-bottom: .125rem;
}

    .nav-item[b-1u7rzq3ewc]  .nav-link {
        color: var(--yf-menu-fg);
        background: none;
        border: none;
        border-radius: 6px;
        height: 2rem;
        padding: 0 .625rem;
        display: flex;
        align-items: center;
        line-height: 2rem;
        width: 100%;
    }

.nav-item[b-1u7rzq3ewc]  .nav-link:hover {
    background-color: var(--yf-menu-active-bg);
    color: var(--yf-menu-fg);
}

/* The current page: the highlight, its text and icon in the highlight text color, and a touch
   bolder, so it is found by weight as well as by color. */
.nav-item[b-1u7rzq3ewc]  a.active {
    background-color: var(--yf-menu-active-bg);
    color: var(--yf-menu-active-fg);
    font-weight: 600;
}

    .nav-item[b-1u7rzq3ewc]  a.active .nav-icon {
        background-color: var(--yf-menu-active-fg);
    }

/* 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-1u7rzq3ewc] {
    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. */
}

/* Worker version and copyright, under Feedback: small and quiet. Lined up with the icons. */
.nav-legal[b-1u7rzq3ewc] {
    padding-top: .5rem;
    padding-bottom: .75rem;
    padding-left: 1.625rem !important;
    font-size: .7rem;
    line-height: 1.4;
    color: var(--yf-menu-muted);
}
/* /Components/Layout/OwnedSessions.razor.rz.scp.css */
/* Start without a machine and the technician's own open sessions, under the links in the left
   panel (owner, 2026-10-11: moved below the Operator group so a changing list never moves a link).
   In the menu's own colors (themes.css, Menu group), so they follow the scheme.

   ::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-z77rfqd2u0] {
    border-top: 1px solid var(--yf-menu-line);
    margin-top: .75rem;
    padding-top: .75rem;
    padding-bottom: .5rem;
}

.nav-sessions-title[b-z77rfqd2u0] {
    font-size: .7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .08em;
    color: var(--yf-menu-muted);
    margin: .5rem 0 .25rem;
    padding: 0 .625rem;
}

.nav-sessions ul[b-z77rfqd2u0] {
    list-style: none;
    margin: 0;
    padding: 0;
}

.nav-sessions[b-z77rfqd2u0]  .nav-session {
    display: flex;
    align-items: center;
    gap: .6rem;
    padding: .3rem .625rem;
    border-radius: 6px;
    color: var(--yf-menu-fg);
    text-decoration: none;
    font-size: .85rem;
}

    .nav-sessions[b-z77rfqd2u0]  .nav-session:hover {
        background: var(--yf-menu-active-bg);
        color: var(--yf-menu-fg);
    }

    /* 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-z77rfqd2u0]  .nav-session.active {
        background: var(--yf-menu-active-bg);
        color: var(--yf-menu-active-fg);
        font-weight: 600;
    }

/* 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-z77rfqd2u0]  .dot {
    width: .5rem;
    height: .5rem;
    border-radius: 50%;
    background: var(--yf-menu-muted);
    flex-shrink: 0;
}

    .nav-sessions[b-z77rfqd2u0]  .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-z77rfqd2u0]  .nav-session-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Sessions this technician opened but does not own now (left, or taken over). Dimmed and with
   a hollow dot, so they read as "yours, but parked" and never as a second attention signal. */
.nav-sessions[b-z77rfqd2u0]  .nav-session-opened {
    opacity: .7;
}

    .nav-sessions[b-z77rfqd2u0]  .nav-session-opened:hover,
    .nav-sessions[b-z77rfqd2u0]  .nav-session-opened.active {
        opacity: 1;
    }

.nav-sessions[b-z77rfqd2u0]  .dot-hollow {
    background: transparent;
    border: 1.5px solid var(--yf-menu-muted);
    box-sizing: border-box;
}

/* Who holds it now. Never squeezed: the name gives way first. */
.nav-sessions[b-z77rfqd2u0]  .nav-session-status {
    margin-left: auto;
    font-size: .7rem;
    color: var(--yf-menu-muted);
    white-space: nowrap;
    flex-shrink: 0;
}
/* /Components/Layout/ReconnectModal.razor.rz.scp.css */
.components-reconnect-first-attempt-visible[b-34lclwdje2],
.components-reconnect-repeated-attempt-visible[b-34lclwdje2],
.components-reconnect-failed-visible[b-34lclwdje2],
.components-pause-visible[b-34lclwdje2],
.components-resume-failed-visible[b-34lclwdje2],
.components-rejoining-animation[b-34lclwdje2] {
    display: none;
}

#components-reconnect-modal.components-reconnect-show .components-reconnect-first-attempt-visible[b-34lclwdje2],
#components-reconnect-modal.components-reconnect-show .components-rejoining-animation[b-34lclwdje2],
#components-reconnect-modal.components-reconnect-paused .components-pause-visible[b-34lclwdje2],
#components-reconnect-modal.components-reconnect-resume-failed .components-resume-failed-visible[b-34lclwdje2],
#components-reconnect-modal.components-reconnect-retrying[b-34lclwdje2],
#components-reconnect-modal.components-reconnect-retrying .components-reconnect-repeated-attempt-visible[b-34lclwdje2],
#components-reconnect-modal.components-reconnect-retrying .components-rejoining-animation[b-34lclwdje2],
#components-reconnect-modal.components-reconnect-failed[b-34lclwdje2],
#components-reconnect-modal.components-reconnect-failed .components-reconnect-failed-visible[b-34lclwdje2] {
    display: block;
}


#components-reconnect-modal[b-34lclwdje2] {
    background-color: var(--bs-body-bg);
    width: 20rem;
    margin: 20vh auto;
    padding: 2rem;
    border: 0;
    border-radius: 0.5rem;
    box-shadow: 0 3px 6px 2px var(--yf-shadow);
    opacity: 0;
    transition: display 0.5s allow-discrete, overlay 0.5s allow-discrete;
    animation: components-reconnect-modal-fadeOutOpacity-b-34lclwdje2 0.5s both;
    &[open]

{
    animation: components-reconnect-modal-slideUp-b-34lclwdje2 1.5s cubic-bezier(.05, .89, .25, 1.02) 0.3s, components-reconnect-modal-fadeInOpacity-b-34lclwdje2 0.5s ease-in-out 0.3s;
    animation-fill-mode: both;
}

}

#components-reconnect-modal[b-34lclwdje2]::backdrop {
    background-color: var(--yf-shadow);
    animation: components-reconnect-modal-fadeInOpacity-b-34lclwdje2 0.5s ease-in-out;
    opacity: 1;
}

@keyframes components-reconnect-modal-slideUp-b-34lclwdje2 {
    0% {
        transform: translateY(30px) scale(0.95);
    }

    100% {
        transform: translateY(0);
    }
}

@keyframes components-reconnect-modal-fadeInOpacity-b-34lclwdje2 {
    0% {
        opacity: 0;
    }

    100% {
        opacity: 1;
    }
}

@keyframes components-reconnect-modal-fadeOutOpacity-b-34lclwdje2 {
    0% {
        opacity: 1;
    }

    100% {
        opacity: 0;
    }
}

.components-reconnect-container[b-34lclwdje2] {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1rem;
}

#components-reconnect-modal p[b-34lclwdje2] {
    margin: 0;
    text-align: center;
}

#components-reconnect-modal button[b-34lclwdje2] {
    border: 0;
    background-color: var(--brand-blue);
    color: var(--yf-on-color);
    padding: 4px 24px;
    border-radius: 4px;
}

    #components-reconnect-modal button:hover[b-34lclwdje2] {
        background-color: var(--brand-blue);
    }

    #components-reconnect-modal button:active[b-34lclwdje2] {
        background-color: var(--brand-blue);
    }

.components-rejoining-animation[b-34lclwdje2] {
    position: relative;
    width: 80px;
    height: 80px;
}

    .components-rejoining-animation div[b-34lclwdje2] {
        position: absolute;
        border: 3px solid var(--brand-blue);
        opacity: 1;
        border-radius: 50%;
        animation: components-rejoining-animation-b-34lclwdje2 1.5s cubic-bezier(0, 0.2, 0.8, 1) infinite;
    }

        .components-rejoining-animation div:nth-child(2)[b-34lclwdje2] {
            animation-delay: -0.5s;
        }

@keyframes components-rejoining-animation-b-34lclwdje2 {
    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/Layout/SessionNotes.razor.rz.scp.css */
/* Copies of the panel's section styles, for the same reason ModelSettings.razor.css and
   AutoApproveSettings.razor.css give: a .razor.css is scoped to its own component, so the ones
   in Diagnose.razor.css cannot reach this markup. The list and hint match what Notes looked like
   when it was part of Diagnose's Machine section; the box and button match the machine page's
   editor (MachineNotesEditor.razor.css). */

.panel-section[b-ni0d97ki2y] {
  margin-top: 1.1rem;
  padding-top: .9rem;
  border-top: 1px solid var(--yf-border);
}

.panel-section summary[b-ni0d97ki2y] {
  cursor: pointer;
}

.panel-title[b-ni0d97ki2y] {
  margin: 0 0 .4rem;
  font-size: .95rem;
  font-weight: 600;
}

.muted[b-ni0d97ki2y] {
  color: var(--yf-muted);
}

.notes[b-ni0d97ki2y] {
  margin: 0 0 .5rem;
  padding-left: 1.1rem;
  font-size: .85rem;
}

.notes li[b-ni0d97ki2y] {
  margin: .25rem 0;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.notes-new[b-ni0d97ki2y] {
  display: block;
  margin-top: .5rem;
  font-size: .85rem;
  font-weight: 600;
}

textarea[b-ni0d97ki2y] {
  display: block;
  box-sizing: border-box;
  width: 100%;
  margin-top: .25rem;
  padding: .4rem;
  font: inherit;
  font-size: .85rem;
  border: 1px solid var(--yf-border);
  border-radius: .25rem;
  resize: vertical;
}

.notes-actions[b-ni0d97ki2y] {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .75rem;
  margin-top: .4rem;
  font-size: .85rem;
}

.notes-actions button[b-ni0d97ki2y] {
  padding: .25rem .75rem;
  font-size: .85rem;
  border: 1px solid var(--yf-border);
  border-radius: .25rem;
  background: var(--bs-body-bg);
  cursor: pointer;
}

.notes-actions button.primary[b-ni0d97ki2y] {
  border-color: var(--brand-blue);
  background: var(--brand-blue);
  color: var(--yf-on-color);
}

.notes-actions button:disabled[b-ni0d97ki2y] {
  opacity: .5;
  cursor: default;
}

.notes-edit[b-ni0d97ki2y] {
  font-size: .85rem;
}

.notes-error[b-ni0d97ki2y] {
  margin: .4rem 0 0;
  font-size: .8rem;
  color: var(--yf-danger-fg);
}

.notes-hint[b-ni0d97ki2y] {
  margin: .4rem 0 0;
  font-size: .75rem;
}
/* /Components/Machines/ConnectionButton.razor.rz.scp.css */
.conn[b-sprxtcdrmf] {
    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-sprxtcdrmf] {
    background: var(--brand-orange);
    border-color: var(--brand-orange);
    color: var(--yf-on-orange);
}

/* In Session, but the worker has dropped (ConnectionButton): the In Session yellow, very light. */
.conn-session-offline[b-sprxtcdrmf] {
    background: var(--bs-body-bg);
    border-color: var(--brand-orange);
    color: var(--yf-danger-fg);
}

.conn-available[b-sprxtcdrmf] {
    background: var(--yf-success);
    border-color: var(--yf-success);
    color: var(--yf-on-color);
}

/* 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-sprxtcdrmf],
.conn-offline:disabled[b-sprxtcdrmf] {
    background: var(--bs-body-bg);
    border-color: var(--yf-border);
    color: var(--yf-muted);
    cursor: default;
    opacity: 1;
}

/* Offline, but a session can still be started to talk to the assistant (owner, 2026-10-07):
   the same grey, with a pointer and a hover so it reads as pressable without looking live. */
.conn-offline-chat:not(:disabled)[b-sprxtcdrmf] {
    cursor: pointer;
}

.conn-offline-chat:not(:disabled):hover[b-sprxtcdrmf] {
    border-color: var(--yf-muted);
    color: var(--bs-body-color);
}

/* Connected but nothing allowed (ConnectionButton): the Available green, very light. */
.conn-unavailable[b-sprxtcdrmf],
.conn-unavailable:disabled[b-sprxtcdrmf] {
    background: var(--bs-body-bg);
    border-color: var(--yf-border);
    color: var(--yf-success-fg);
    cursor: default;
    opacity: 1;
}

.conn:disabled:not(.conn-offline):not(.conn-unavailable)[b-sprxtcdrmf] {
    opacity: 0.6;
    cursor: default;
}

.conn-error[b-sprxtcdrmf] {
    margin-left: 0.5rem;
    font-size: 0.8rem;
    color: var(--yf-danger-fg);
}
/* /Components/Machines/MachineNotesEditor.razor.rz.scp.css */
/* Machine Notes pane on the machine page. */
/* Same card as the page's other sections (.page-section in app.css). */
.notes-pane[b-4lua29vzau] {
  margin: 1.25rem 0;
  border: 1px solid var(--yf-border);
  border-radius: 12px;
  padding: 1.25rem 1.5rem 1.5rem;
  background: var(--bs-body-bg);
}

.notes-pane h2[b-4lua29vzau] {
  margin: 0 0 .5rem;
}

.notes-help[b-4lua29vzau],
.notes-example[b-4lua29vzau] {
  font-size: .875rem;
  margin: 0 0 .6rem;
}

.notes-example[b-4lua29vzau] {
  padding: .5rem .65rem;
  border-left: 3px solid var(--brand-blue);
  background: var(--bs-body-bg);
}

.notes-list[b-4lua29vzau] {
  list-style: none;
  padding: 0;
  margin: .75rem 0;
}

.notes-list li[b-4lua29vzau] {
  padding: .6rem 0;
  border-top: 1px solid var(--yf-border);
}

.notes-body[b-4lua29vzau] {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.notes-meta[b-4lua29vzau] {
  font-size: .75rem;
  margin-top: .2rem;
}

.notes-new[b-4lua29vzau] {
  display: block;
  font-weight: 600;
  margin-top: .5rem;
}

textarea[b-4lua29vzau] {
  display: block;
  width: 100%;
  margin-top: .25rem;
  padding: .4rem;
  font: inherit;
  font-weight: normal;
  border: 1px solid var(--yf-border);
  border-radius: .25rem;
  resize: vertical;
}

.notes-actions[b-4lua29vzau] {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .5rem;
  margin-top: .4rem;
  font-size: .85rem;
}

.notes-actions button[b-4lua29vzau] {
  padding: .3rem .8rem;
  font-size: .85rem;
  border: 1px solid var(--yf-border);
  border-radius: .25rem;
  background: var(--bs-body-bg);
  cursor: pointer;
}

.notes-actions button.primary[b-4lua29vzau] {
  border-color: var(--brand-blue);
  background: var(--brand-blue);
  color: var(--yf-on-color);
}

.notes-actions button.danger-button[b-4lua29vzau] {
  border-color: var(--yf-danger);
  background: var(--yf-danger);
  color: var(--yf-on-color);
}

.notes-actions button:disabled[b-4lua29vzau] {
  opacity: .5;
  cursor: default;
}

.muted[b-4lua29vzau] {
  color: var(--yf-muted);
}

.notes-hint[b-4lua29vzau] {
  font-size: .75rem;
  margin: .6rem 0 0;
}

.notice[b-4lua29vzau] {
  padding: .5rem .7rem;
  border-radius: .25rem;
}

.notice-error[b-4lua29vzau] {
  background-color: var(--bs-body-bg);
  color: var(--yf-danger-fg);
}
/* /Components/Machines/MachineTable.razor.rz.scp.css */
.work-section[b-jgi039dah5] {
    margin-bottom: 2rem;
}

.work-section h2[b-jgi039dah5] {
    font-size: 1.1rem;
    margin-bottom: 0.5rem;
}

.count[b-jgi039dah5] {
    display: inline-block;
    min-width: 1.5rem;
    padding: 0 0.4rem;
    border-radius: 1rem;
    background: var(--bs-body-bg);
    color: var(--yf-muted);
    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.

   overflow-x came with the four update columns (Worker Auto-Update v1, 5.5). Every cell in this
   table is nowrap by design -- a wrapped hostname or version is harder to scan than a scrollbar
   -- so eleven columns on a laptop have to be reachable sideways rather than squeezed. */
.work-scroll[b-jgi039dah5] {
    max-height: 18rem;
    overflow-y: auto;
    overflow-x: auto;
    border: 1px solid var(--yf-border);
    border-radius: 0.25rem;
}

/* A customer's page (MachineTable OnCustomerPage): 50% taller. */
.work-scroll-tall[b-jgi039dah5] {
    max-height: 27rem;
}

/* Last in its card (.page-section on the customer page): the card's padding is the gap. */
.work-section:last-child[b-jgi039dah5] {
    margin-bottom: 0;
}

/* .work's padding, borders and header type are global (app.css), so the tables on the machine
   page and its panels get them too. What is only the machine list's: a header that stays put
   while the list scrolls under it. */
.work th[b-jgi039dah5] {
    position: sticky;
    top: 0;
    background: var(--bs-body-bg);
    z-index: 1;
}

/* A machine worth a technician's attention during a rollout: it needs a person, it went quiet
   after it was offered something, it would update with no way back, or something has failed on
   it before. **Not** "it is not on the offered version" -- during a staged rollout most of the
   fleet is deliberately behind, and colouring all of it buries the few rows that matter.

   This class was referenced by the old /fleet page and never defined anywhere, so the rows it
   was meant to pick out looked exactly like every other row. */
.work tr.row-warn td[b-jgi039dah5] {
    background: var(--bs-body-bg);
}

/* A soft-deleted machine shown on the customer page via "show deleted". Muted rather than
   coloured: it is here to be acknowledged and left alone, not to be acted on. Scoped CSS does
   not reach a global .muted, so the row is dimmed the same way the Customers page dims an
   inactive row. */
.work tr.muted td[b-jgi039dah5] {
    color: var(--yf-muted);
}
/* /Components/Markup/RichText.razor.rz.scp.css */
/* The rt-* rules that used to be here now live in wwwroot/app.css, unscoped.

   They are shared with js/diagnose.js, which builds the same elements with the same class names
   while a turn is streaming (SessionTranscript.razor, .live-prose). CSS isolation stamps its
   scope attribute at compile time onto elements written in markup, and elements built in script
   never get it, so a scoped rule here would style the finished table and not the one being
   typed. One home for the rules is what keeps the two from drifting apart mid-turn.

   What stays here is the bare element selector, which has no business being global. */

/* 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-h9vetumiyi] {
  margin: .25rem 0;
  white-space: pre-wrap;
}
/* /Components/Pages/Connections.razor.rz.scp.css */
/* A row's actions: Report and Delete, spaced apart with a dot between two, as on the shop's
   Connections page (ShopConnections.razor.css). The Delete button is ConfirmButton's own. */
.acts[b-zzpqni7fqr] {
    white-space: nowrap;
    text-align: right;
}

.act[b-zzpqni7fqr] {
    display: inline-flex;
    align-items: center;
}

.act + .act[b-zzpqni7fqr]::before {
    content: "·";
    margin: 0 .6rem;
    color: var(--yf-muted);
}

/* Delete all, at the right end of the heading row. */
.delete-all[b-zzpqni7fqr] {
    margin-left: auto;
}
/* /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-f5nq7ube5v] {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin-bottom: 0.75rem;
}

.cust-search[b-f5nq7ube5v] {
    flex: 0 1 22rem;
    padding: 0.4rem 0.6rem;
    font-size: 1rem;
    border: 1px solid var(--yf-border);
    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-f5nq7ube5v] {
    display: inline-block;
    min-width: 1.5rem;
    padding: 0 0.4rem;
    border-radius: 1rem;
    background: var(--bs-body-bg);
    color: var(--yf-muted);
    font-size: 0.8rem;
    text-align: center;
}

.cust-tools .edit-link[b-f5nq7ube5v] {
    margin-left: auto;
    font-size: 0.9rem;
}

.cust-scroll[b-f5nq7ube5v] {
    max-height: 32rem;
    overflow-y: auto;
    border: 1px solid var(--yf-border);
    border-radius: 0.25rem;
}

.cust[b-f5nq7ube5v] {
    width: 100%;
    border-collapse: collapse;
}

.cust th[b-f5nq7ube5v],
.cust td[b-f5nq7ube5v] {
    text-align: left;
    padding: 0.4rem 0.75rem;
    border-bottom: 1px solid var(--yf-border);
    vertical-align: middle;
    white-space: nowrap;
}

.cust th[b-f5nq7ube5v] {
    position: sticky;
    top: 0;
    background: var(--bs-body-bg);
    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-f5nq7ube5v] {
    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: var(--yf-muted);
    text-align: inherit;
    cursor: pointer;
}

.cust th .sort:hover[b-f5nq7ube5v] {
    color: var(--bs-body-color);
}

.cust th .arrow[b-f5nq7ube5v] {
    /* 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-f5nq7ube5v],
.cust td.num[b-f5nq7ube5v] {
    text-align: center;
}

.cust tr.inactive td[b-f5nq7ube5v] {
    color: var(--yf-muted);
}

/* .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-f5nq7ube5v] {
    color: var(--yf-muted);
}
/* /Components/Pages/Dashboard.razor.rz.scp.css */
/* The Dashboard's three charts: side by side when there is room, stacked on a phone. */
.dash-charts[b-1nu7xssuu3] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
    gap: 1rem;
    margin-bottom: 1rem;
}

    .dash-charts .dash-chart[b-1nu7xssuu3] {
        margin: 0;
    }

.dash-link[b-1nu7xssuu3] {
    margin: .75rem 0 0;
    font-size: .85rem;
    text-align: center;
}

.dash-note[b-1nu7xssuu3] {
    font-size: .85rem;
}

/* Under the charts: the oldest open issues, and the time to resolution. */
.dash-more[b-1nu7xssuu3] {
    margin: -1.75rem 0 0;
    font-size: .85rem;
}

.dash-stat[b-1nu7xssuu3] {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: .5rem;
    margin-bottom: .75rem;
}

.dash-stat-value[b-1nu7xssuu3] {
    font-size: 1.6rem;
    font-weight: 600;
}

.count[b-1nu7xssuu3] {
    display: inline-block;
    min-width: 1.5rem;
    padding: 0 0.4rem;
    border-radius: 1rem;
    background: var(--bs-body-bg);
    color: var(--yf-muted);
    font-size: 0.8rem;
    text-align: center;
    vertical-align: middle;
}
/* /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-qifbz75a8f] {
  display: flex;
  flex-direction: column;
  min-height: calc(100vh - 6rem);
}

.dock[b-qifbz75a8f] {
  margin-top: auto;
  position: sticky;
  bottom: 0;
  background: var(--brand-blue);
  /* Out to the blue's visible edges (owner, 2026-10-07): .shell-content's 1.5rem side padding,
     taken back with negative side margins, so every row -- Stop, the ownership strip, the
     compose box -- starts 10px from the blue's left edge and the toggle and Send end 10px from
     its right. Side margins only: the vertical ones are what upset sticky (see ::before). */
  margin-left: -1.5rem;
  margin-right: -1.5rem;
  padding: 10px;
  /* 10px of blue under the compose box (owner, 2026-10-07; .shell-content has no bottom
     padding under it any more, .has-dock in app.css). */
  padding-bottom: 10px;
  box-shadow: 0 -2px 8px var(--yf-shadow);
}

/* 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-qifbz75a8f]::before {
  content: "";
  position: absolute;
  z-index: -1;
  top: 0;
  /* Flush with the dock's bottom: .shell-content has no bottom padding under it any more
     (.has-dock, app.css, owner 2026-10-07). */
  bottom: 0;
  /* The dock's own box now reaches the panel's edges (its negative side margins above). */
  left: 0;
  right: 0;
  background: var(--brand-blue);
}

/* 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-qifbz75a8f] {
  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 var(--yf-border);
  background: var(--bs-body-bg);
  color: var(--yf-muted);
  box-shadow: 0 2px 8px var(--yf-shadow);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

.jump-to-bottom:hover[b-qifbz75a8f] {
  background: var(--bs-body-bg);
}

.jump-to-bottom svg[b-qifbz75a8f] {
  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-qifbz75a8f] {
  margin-top: .5rem;
}

/* Collapse toggle (owner, 2026-10-06). The down arrow sits in the dock's top right corner,
   absolutely placed so it takes no row of its own; the dock keeps room for it on the right. */
.dock[b-qifbz75a8f] { padding-right: 2.75rem; }

.dock-toggle[b-qifbz75a8f] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  padding: 0;
  border: 1px solid var(--yf-on-color-soft);
  border-radius: .3rem;
  background: transparent;
  color: var(--yf-on-color);
  cursor: pointer;
}

.dock-toggle:hover[b-qifbz75a8f] { background: var(--yf-on-color-soft); }

.dock-toggle svg[b-qifbz75a8f] {
  width: 1.1rem;
  height: 1.1rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 2.25;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Overrides .dock > * + *: the toggle is first in the dock but must not push anything down. */
.dock-collapse[b-qifbz75a8f] {
  position: absolute;
  /* 10px in from the top and the right, the same as Stop on the left and Send below it. */
  top: 10px;
  right: 10px;
  margin-top: 0;
}

/* ...and the row after it keeps its old place as the first row. */
.dock-collapse + *[b-qifbz75a8f] { margin-top: 0; }

/* The compose row uses the room kept for the toggle (owner, 2026-10-07): the toggle sits in the
   top right corner, so a compose row with any row above it runs out to the dock's right
   padding, Send ending 10px from the blue's edge, right under the toggle's right edge. When
   the compose row is the first row it stays clear of the toggle. */
.dock > :not(.dock-collapse) + .compose[b-qifbz75a8f] { margin-right: calc(10px - 2.75rem); }

/* Folded: everything but the bar and the jump-to-latest button is hidden, so the dock is one
   short row and the transcript gets the rest of the screen. */
.dock-collapsed[b-qifbz75a8f] {
  padding-top: 4px;
  padding-bottom: 4px;
  padding-right: 10px;
}

.dock-collapsed > :not(.dock-bar):not(.jump-to-bottom)[b-qifbz75a8f] { display: none; }

.dock-bar[b-qifbz75a8f] {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
  color: var(--yf-on-color);
  font-size: .8rem;
}

.muted[b-qifbz75a8f] { color: var(--yf-muted); font-size: .875rem; }
.error[b-qifbz75a8f] { color: var(--yf-danger-fg); }

/* 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 "YouFixIt.ai" 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-qifbz75a8f] {
  position: fixed;
  z-index: 4;
  left: calc(var(--nav-w) + 1.5rem);
  top: 0;
  height: 3rem;
  display: flex;
  align-items: center;
  gap: .75rem;
  /* The bar's blue, so the strip covers the bar's own shop name underneath it: the strip
     carries its own copy as its first item (owner, 2026-10-02). Covering it rather than hiding
     it with a :has() rule, which re-matched on every DOM change while a turn streamed. */
  background: var(--brand-blue);
  padding-right: .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 "YouFixIt.ai" 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, "YouFixIt.ai" itself, and one more .5rem gap. */
html.nav-collapsed .bar-session[b-qifbz75a8f] {
  left: 9rem;
}

.bar-name[b-qifbz75a8f] { color: var(--yf-on-color); 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-qifbz75a8f] { text-decoration: none; }
a.bar-name:hover[b-qifbz75a8f] { text-decoration: underline; }
/* Shop - Customer - Computer, tight together, the dashes dimmed (owner, 2026-10-03). The
   shop name's own right margin (app.css) is dropped inside the group. */
.bar-title[b-qifbz75a8f] { display: inline-flex; align-items: center; gap: .4rem; min-width: 0; white-space: nowrap; }
.bar-session .bar-title .shell-shop[b-qifbz75a8f] { margin: 0; }
.bar-sep[b-qifbz75a8f] { color: var(--yf-on-color); }
.inv dd a[b-qifbz75a8f] { color: var(--brand-blue-fg); }
.bar-muted[b-qifbz75a8f] { color: var(--yf-on-color); font-size: .8rem; }

.bar-cancel[b-qifbz75a8f] {
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  font-size: .8rem;
  color: var(--yf-on-color);
  text-decoration: underline;
  cursor: pointer;
}

.bar-cancel:hover[b-qifbz75a8f] {
  color: var(--yf-on-color);
}

/* The .state pill's own rules moved to wwwroot/app.css when the pill became StatePill.razor:
   they are scoped to this page, and the pill's markup now belongs to another component, which
   carries a different scope attribute. They sit next to .dots there, which was already global
   for the same reason — the two are one pill. */

.workers[b-qifbz75a8f] { list-style: none; padding: 0; }
.workers li[b-qifbz75a8f] { display: flex; align-items: center; gap: .75rem; padding: .5rem 0; border-bottom: 1px solid var(--yf-border); }

/* 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-qifbz75a8f] {
  /* --live-headroom is set by js/diagnose.js while a turn is streaming: ten lines of empty
     space under it, so the text grows into room it already has instead of pushing the page
     down a line at a time. Zero the rest of the time. */
  padding-bottom: calc(var(--dock-h, 12rem) + 14px + var(--live-headroom, 0px));
}

/* 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-qifbz75a8f] {
  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-qifbz75a8f] .entry {
  scroll-margin-bottom: calc(var(--dock-h, 0px) + 1rem);
}

.proposal[b-qifbz75a8f] { border: 2px solid var(--brand-orange); border-radius: .5rem; padding: 1rem; background: var(--bs-body-bg); }
.proposal-head[b-qifbz75a8f] { 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-qifbz75a8f] {
  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-qifbz75a8f] {
  color: var(--brand-blue-fg);
}

.why[b-qifbz75a8f] { margin: .5rem 0; }
.tier[b-qifbz75a8f] { font-size: .75rem; padding: .1rem .4rem; border-radius: .25rem; background: var(--bs-body-bg); }
.tier-changesettings[b-qifbz75a8f] { background: var(--yf-warning-soft); }
.tier-write[b-qifbz75a8f] { background: var(--yf-danger-soft); }
/* Data Loss (catalog 1.27.0): above Write, so a step darker. #7f1d1d on #fca5a5 is 5.3:1. */
.tier-dataloss[b-qifbz75a8f] { background: var(--yf-danger-soft); color: var(--yf-danger-fg); font-weight: 600; }
/* 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-qifbz75a8f] {
  background: none;
  border: 1px solid var(--yf-muted);
  color: var(--yf-muted);
  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-qifbz75a8f] { display: grid; grid-template-columns: auto 1fr; gap: .25rem .75rem; margin: .5rem 0; }
dt[b-qifbz75a8f] { font-weight: 600; font-size: .875rem; }
dd[b-qifbz75a8f] { 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-qifbz75a8f] {
  display: flex;
  gap: .75rem;
  align-items: stretch;
  margin-top: .75rem;
}

.action-buttons[b-qifbz75a8f] {
  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-qifbz75a8f] {
  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-qifbz75a8f] {
  flex: 1;
  min-width: 0;
  height: 3.4rem;
  padding: .4rem;
  font: inherit;
  resize: vertical;
}
button[b-qifbz75a8f] { padding: .4rem .9rem; cursor: pointer; }
/* Light green and light red (owner, 2026-10-04), with dark text of the same hue so the label
   still reads, and a border a shade darker so the button does not fade into a light card. */
.approve[b-qifbz75a8f] { background: var(--yf-success-soft); color: var(--yf-success-fg); border: 1px solid var(--yf-success-fg); border-radius: .25rem; }
.approve:hover:not(:disabled)[b-qifbz75a8f] { background: var(--yf-success-soft); }
.reject[b-qifbz75a8f] { background: var(--yf-danger-soft); color: var(--yf-danger-fg); border: 1px solid var(--yf-danger-fg); border-radius: .25rem; }
.reject:hover:not(:disabled)[b-qifbz75a8f] { background: var(--yf-danger-soft); }

.compose[b-qifbz75a8f] { 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-qifbz75a8f] {
  flex: 1;
  /* Smaller with the font below (owner, 2026-10-06), and border-box so the height here is the
     whole box, padding and border included, the same as the Send button's: two lines at rest,
     five at most. js/diagnose.js adds the border back when it grows the box. */
  box-sizing: border-box;
  height: 2.95rem;
  min-height: 2.95rem;
  /* 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: 6.7rem;
  padding: .15rem .5rem;
  background: var(--bs-body-bg);
  border: 1px solid var(--yf-border);
  border-radius: .25rem;
  font: inherit;
  /* The same size as the Send button's text beside it (owner, 2026-10-07): 1rem.
     height/min-height/max-height above are scaled to match, so two lines still fit at rest
     and five lines at the max (5 x 1.25rem + padding + border). */
  font-size: 1rem;
  line-height: 1.25;
  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-qifbz75a8f] {
  box-sizing: border-box;
  /* Send 4px smaller each way than the message box beside it (owner, 2026-10-07). */
  height: calc(2.95rem - 4px);
  padding: 0 calc(.9rem - 2px);
  display: inline-flex;
  align-items: center;
}

.compose .send[b-qifbz75a8f] { font-weight: 600; } /* bold like Save to customer (owner, 2026-10-07) */

/* 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-qifbz75a8f] {
  border-left: 3px solid var(--yf-border);
}

.compose textarea:focus[b-qifbz75a8f] {
  outline: 2px solid var(--brand-blue);
  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-qifbz75a8f] {
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: .35rem 1rem;
  margin: .5rem 0;
  border: 1px solid var(--yf-danger-fg);
  border-radius: .5rem;
  background: var(--bs-body-bg);
}
.retry span[b-qifbz75a8f] { color: var(--yf-danger-fg); font-size: .8rem; }
/* Green, the same as Save to customer (owner, 2026-10-07): trying again is the way forward,
   not a warning; the red is the message beside it. */
.retry button[b-qifbz75a8f] {
  background: var(--yf-success);
  color: var(--yf-on-color);
  border: none;
  border-radius: .25rem;
  padding: .15rem .6rem;
  font-size: .8rem;
  cursor: pointer;
}

.retry button:hover:not(:disabled)[b-qifbz75a8f] { filter: brightness(1.1); }
.retry button:disabled[b-qifbz75a8f] { opacity: .5; cursor: default; }

.working-row[b-qifbz75a8f] { 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.) */
/* Danger tint with a Danger text border (owner, 2026-10-07): on the blue bar the dark scheme's
   tint alone is barely a shape, so the outline is what marks it as a button. */
.stop[b-qifbz75a8f] {
  background: var(--yf-danger-soft);
  color: var(--yf-danger-fg);
  border: 1px solid var(--yf-danger-fg);
  font-weight: 600; /* bold like Save to customer (owner, 2026-10-07) */
  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-qifbz75a8f] {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .5rem;
  padding: .75rem 1rem;
  border: 1px solid var(--brand-orange);
  border-left: 4px solid var(--brand-orange);
  border-radius: .25rem;
  background: var(--bs-body-bg);
}
.lost span[b-qifbz75a8f] { 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. The button is rendered
   by ConfirmButton (ButtonClass="disconnect"), so these rules reach into it with ::deep from the
   two places it sits. */
.bar-session[b-qifbz75a8f]  .disconnect,
.session-controls[b-qifbz75a8f]  .disconnect {
  /* 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.

     Text on orange (--yf-on-orange), white (owner, 2026-10-07), the same as every orange
     button. About 3:1 on this orange; a darker orange fill would raise it. 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);
  color: var(--yf-on-orange);
  border: none;
  border-radius: .25rem;
  padding: .25rem .75rem;
  font-size: .8rem;
  font-weight: 600; /* bold like Save to customer (owner, 2026-10-07) */
  cursor: pointer;
}

.bar-session[b-qifbz75a8f]  .disconnect:hover,
.session-controls[b-qifbz75a8f]  .disconnect:hover {
  background: var(--brand-orange);
    color: var(--yf-on-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-qifbz75a8f] {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: .3rem .75rem;
  margin: 0 0 .75rem;
  font-size: .85rem;
}

.inv dt[b-qifbz75a8f] {
  color: var(--yf-muted);
  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-qifbz75a8f] {
  margin: 0;
  overflow-wrap: anywhere;
  font-family: inherit;
  font-size: inherit;
}

.inv-when[b-qifbz75a8f] {
  margin: 0 0 .75rem;
}

.inv-json summary[b-qifbz75a8f] {
  cursor: pointer;
  font-size: .8rem;
  color: var(--brand-blue-fg);
}

.inv-json pre[b-qifbz75a8f] {
  margin: .5rem 0 0;
  padding: .5rem;
  background: var(--bs-body-bg);
  border: 1px solid var(--yf-border);
  border-radius: .25rem;
  font-size: .75rem;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  max-height: 28rem;
  overflow-y: auto;
}

.panel-title[b-qifbz75a8f] {
  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 (the
   first thing in the panel) doesn't grow a border of its own — only a .panel-section that follows another one, like Technician Settings after Machine,
   gets the separator. */
.panel-section summary[b-qifbz75a8f] {
  cursor: pointer;
}

.panel-section > p[b-qifbz75a8f] {
  margin: 0 0 .75rem;
}

.panel-section + .panel-section[b-qifbz75a8f] {
  margin-top: 1.1rem;
  padding-top: .9rem;
  border-top: 1px solid var(--yf-border);
}

.toggle-row[b-qifbz75a8f] {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
  padding: .35rem 0;
  font-size: .85rem;
  cursor: pointer;
}

.toggle-row input[b-qifbz75a8f] {
  cursor: pointer;
}

/* 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-qifbz75a8f] {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .5rem .75rem;
  color: var(--yf-on-color);
  font-size: .85rem;
  margin-bottom: .5rem;
}
.ownership .muted[b-qifbz75a8f] { color: var(--yf-on-color); }
.ownership a[b-qifbz75a8f] { color: var(--yf-on-color); }
.ownership .owner-line[b-qifbz75a8f] { margin-right: auto; }
.ownership .own-ask[b-qifbz75a8f] {
  background: var(--bs-body-bg);
  color: var(--yf-danger-fg);
  border-radius: .25rem;
  padding: .15rem .5rem;
}
/* On the blue dock (owner, 2026-10-07): a translucent white fill and a white border rather than
   Brand blue, which vanished into the bar behind it. The same Highlight on color the menu uses
   for hover and the current page. Claim, Approve and Deny keep their green and red below. */
.ownership button[b-qifbz75a8f] {
  border: 1px solid var(--yf-on-color);
  border-radius: .25rem;
  padding: .2rem .7rem;
  font-size: .8rem;
  cursor: pointer;
  color: var(--yf-on-color);
  background: var(--yf-on-color-soft);
}
.ownership button:hover:not(:disabled)[b-qifbz75a8f] { filter: brightness(1.15); }
.ownership button:disabled[b-qifbz75a8f] { opacity: .5; cursor: default; }
.ownership .own-claim[b-qifbz75a8f],
.ownership .own-approve[b-qifbz75a8f] { background: var(--yf-success); border-color: var(--yf-success); }
.ownership .own-deny[b-qifbz75a8f] { background: var(--yf-danger); border-color: var(--yf-danger); }

.stop:disabled[b-qifbz75a8f],
.bar-session[b-qifbz75a8f]  .disconnect:disabled,
.session-controls[b-qifbz75a8f]  .disconnect:disabled { opacity: .5; cursor: default; }

/* Same inline-code look as tool names in the transcript (SessionTranscript.razor.css). */
.tool-name[b-qifbz75a8f] {
  background: var(--bs-body-bg);
  border-radius: .2rem;
  padding: .05rem .35rem;
  font-size: .85em;
}

/* Machine Notes in the right panel. Technician free text, so wrap anything. */
.notes[b-qifbz75a8f] {
  margin: 0 0 .5rem;
  padding-left: 1.1rem;
  font-size: .85rem;
}

.notes li[b-qifbz75a8f] {
  margin: .25rem 0;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.notes-edit[b-qifbz75a8f] {
  font-size: .85rem;
}

.notes-section > p.notes-hint[b-qifbz75a8f] {
  margin: .25rem 0 0;
  font-size: .75rem;
}

/* Notes, nested inside the Machine section with its own toggle. */
.notes-section[b-qifbz75a8f] {
  margin-top: .75rem;
  padding-top: .6rem;
  border-top: 1px solid var(--yf-border);
}

.notes-title[b-qifbz75a8f] {
  cursor: pointer;
  font-size: .85rem;
  font-weight: 600;
  margin-bottom: .4rem;
}

.notes-section > p[b-qifbz75a8f] {
  margin: 0 0 .5rem;
}

/* Stop/Disconnect row at the very top of the dock, above the ownership strip. Reuses .stop
   and .disconnect (both already read on the dock's dark background) and the top bar's
   .bar-muted / .bar-cancel for the confirm label and Cancel link — those are light-on-dark
   already, so they read the same on the dock's #3f3f46 as on the navy bar. */
.session-controls[b-qifbz75a8f] {
  display: flex;
  align-items: center;
  gap: .75rem;
}

/* ---------------------------------------------------------------------------------------
   Pictures and files (owner, 2026-10-06): + and the QR button beside the message box, the
   tray of what will go with the next message, the phone's Take photo bar, and the QR dialog.
   --------------------------------------------------------------------------------------- */
.attach-buttons[b-qifbz75a8f] {
  display: inline-flex;
  gap: .35rem;
  align-self: center;
}

/* .compose to outrank .compose button above. */
.compose .attach-add[b-qifbz75a8f],
.compose .attach-qr[b-qifbz75a8f] {
  box-sizing: border-box;
  /* 40px (owner, 2026-10-07); the + and the QR image keep their size. In px, so a phone's
     smaller root font does not shrink the target. */
  width: 40px;
  height: 40px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--yf-on-color-soft);
  border-radius: .3rem;
  background: transparent;
  color: var(--yf-on-color);
  cursor: pointer;
}

.attach-add[b-qifbz75a8f] { font-size: 1.6rem; line-height: 1; font-weight: 300; }
.attach-add:hover[b-qifbz75a8f], .attach-qr:hover[b-qifbz75a8f] { background: var(--yf-on-color-soft); }

.attach-qr svg[b-qifbz75a8f] {
  width: 1.25rem;
  height: 1.25rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linejoin: round;
}

.attach-tray[b-qifbz75a8f] {
  display: flex;
  flex-wrap: wrap;
  gap: .4rem;
}

.attach-chip[b-qifbz75a8f] {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  max-width: 16rem;
  padding: .2rem .25rem .2rem .2rem;
  border-radius: .3rem;
  background: var(--bs-body-bg);
  color: var(--bs-body-color);
  font-size: .8rem;
}

.attach-chip img[b-qifbz75a8f] {
  width: 2.2rem;
  height: 2.2rem;
  object-fit: cover;
  border-radius: .2rem;
}

.attach-file-icon[b-qifbz75a8f] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.2rem;
  height: 2.2rem;
  border-radius: .2rem;
  background: var(--yf-border);
  font-size: .65rem;
  font-weight: 700;
}

.attach-name[b-qifbz75a8f] {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.attach-remove[b-qifbz75a8f] {
  border: none;
  background: transparent;
  color: inherit;
  font-size: 1.1rem;
  line-height: 1;
  padding: 0 .25rem;
  cursor: pointer;
  opacity: .7;
}

.attach-remove:hover[b-qifbz75a8f] { opacity: 1; }

.attach-notice[b-qifbz75a8f] {
  margin: 0;
  color: var(--yf-on-color);
  font-size: .8rem;
}

.attach-phone[b-qifbz75a8f] {
  display: flex;
  align-items: center;
  gap: .5rem;
}

.attach-phone-btn[b-qifbz75a8f] {
  flex: 1;
  padding: .7rem 1rem;
  border: none;
  border-radius: .4rem;
  background: var(--bs-body-bg);
  color: var(--bs-body-color);
  font-size: 1.05rem;
  font-weight: 600;
  cursor: pointer;
}

.attach-phone-alt[b-qifbz75a8f] {
  background: transparent;
  color: var(--yf-on-color);
  border: 1px solid var(--yf-on-color-soft);
  font-weight: 400;
}

.attach-phone .attach-remove[b-qifbz75a8f] { color: var(--yf-on-color); }

/* The QR dialog: a native <dialog> in the top layer, the same shape as ConfirmButton's. */
.qr-host[b-qifbz75a8f] {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  max-height: none;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  overflow: visible;
  color: inherit;
}

.qr-host[b-qifbz75a8f]::backdrop { background: transparent; }

.qr-backdrop[b-qifbz75a8f] {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  background-color: var(--yf-shadow);
  animation: confirm-fade-in .16s ease-out both;
}

.qr-box[b-qifbz75a8f] {
  width: 100%;
  max-width: 22rem;
  padding: 1.5rem;
  border-radius: .6rem;
  background: var(--bs-body-bg);
  color: var(--bs-body-color);
  box-shadow: 0 20px 45px var(--yf-shadow);
  text-align: center;
  animation: confirm-pop-in .22s cubic-bezier(.2, .9, .3, 1.25) both;
}

.qr-box h2[b-qifbz75a8f] { font-size: 1.15rem; margin: 0 0 .75rem; }
.qr-box p[b-qifbz75a8f] { font-size: .9rem; margin: .75rem 0 0; }

/* The code stays black on white in every scheme: a phone reads that best. */
.qr-code[b-qifbz75a8f] {
  width: 15rem;
  height: 15rem;
  margin: 0 auto;
  padding: .5rem;
  background: #fff;
  border-radius: .3rem;
}

.qr-code[b-qifbz75a8f]  svg { width: 100%; height: 100%; display: block; }

.qr-url[b-qifbz75a8f] {
  font-size: .75rem !important;
  color: var(--yf-muted);
  overflow-wrap: anywhere;
}

.qr-done[b-qifbz75a8f] {
  margin-top: 1rem;
  min-width: 7rem;
  padding: .45rem 1rem;
  border: 1px solid var(--yf-border);
  border-radius: .3rem;
  background: var(--bs-body-bg);
  color: var(--bs-body-color);
  cursor: pointer;
}

/* ---------------------------------------------------------------------------------------
   Anonymous sessions (owner, 2026-10-06): Save to customer beside Disconnect, and the save
   dialog (in .qr-host, the same top-layer dialog as the QR code).
   --------------------------------------------------------------------------------------- */
.save-anon[b-qifbz75a8f] {
  background: var(--yf-success);
  color: var(--yf-on-color);
  border: none;
  border-radius: .25rem;
  padding: .25rem .75rem;
  font-size: .8rem;
  font-weight: 600;
  cursor: pointer;
}

.save-anon:disabled[b-qifbz75a8f] { opacity: .5; cursor: default; }

.save-box[b-qifbz75a8f] {
  max-width: 26rem;
  text-align: left;
}

.save-box h2[b-qifbz75a8f] { text-align: center; }

.save-field[b-qifbz75a8f] {
  display: flex;
  flex-direction: column;
  gap: .2rem;
  margin-top: .75rem;
  font-size: .85rem;
}

.save-field input[b-qifbz75a8f],
.save-field select[b-qifbz75a8f] {
  padding: .4rem .5rem;
  border: 1px solid var(--yf-border);
  border-radius: .25rem;
  background: var(--yf-dropdown-bg);
  color: var(--bs-body-color);
  font-size: .95rem;
}

.save-choice[b-qifbz75a8f] {
  display: flex;
  gap: 1.25rem;
  margin-top: .9rem;
  font-size: .9rem;
}

.save-choice label[b-qifbz75a8f] { display: inline-flex; align-items: center; gap: .35rem; cursor: pointer; }

.save-error[b-qifbz75a8f] {
  color: var(--yf-danger-fg);
  font-size: .85rem !important;
}

.save-actions[b-qifbz75a8f] {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: .5rem;
  margin-top: 1.25rem;
}

.save-actions .qr-done[b-qifbz75a8f] { margin-top: 0; min-width: 0; }

/* Save / Save and disconnect: Success green, the same as the Save to customer button that
   opens this popup (owner, 2026-10-07). Brand blue was 2.3:1 against the dark scheme's popup
   and read as a dark shape on a dark box; green is 3.3:1 there, white text 5.0:1. */
.save-go[b-qifbz75a8f] {
  padding: .45rem 1rem;
  border: 1px solid var(--yf-success);
  border-radius: .3rem;
  background: var(--yf-success);
  color: var(--yf-on-color);
  font-weight: 600;
  cursor: pointer;
}

.save-go:hover:not(:disabled)[b-qifbz75a8f] { filter: brightness(1.1); }
.save-go:disabled[b-qifbz75a8f] { opacity: .6; cursor: default; }

/* ---------------------------------------------------------------------------------------
   Microphone (owner, 2026-10-06): speak instead of typing, phones only. Hidden everywhere
   except a touch screen ((pointer: coarse): the main pointer is a finger) whose browser has
   speech recognition (js/mic.js keeps .yf-speech on <html>). Same size and look as + ; red and
   pulsing while listening.

   (hover: none) dropped (owner, 2026-10-07): some Android phones report hover support, and
   pointer: coarse alone already rules out a desktop with a mouse.
   --------------------------------------------------------------------------------------- */
.compose .mic[b-qifbz75a8f] { display: none; }

/* The QR code's job is to get a photo from a phone onto this page; on the phone itself it is a
   detour, and + already offers the camera (owner, 2026-10-07). */
@media (pointer: coarse) {
  .compose .attach-qr[b-qifbz75a8f] { display: none; }
}

/* + and the QR code in a row; on a phone, + and the microphone side by side, close together
   (owner, 2026-10-07; they were stacked). */
.compose-left[b-qifbz75a8f] {
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  flex: none;
}

.compose-left .attach-buttons[b-qifbz75a8f] { gap: .25rem; }

@media (pointer: coarse) {
  html.yf-speech .compose .mic[b-qifbz75a8f] {
    box-sizing: border-box;
    width: 40px;
    height: 40px;
    padding: 0;
    display: inline-flex;
    flex: none;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--yf-on-color-soft);
    border-radius: .3rem;
    background: transparent;
    color: var(--yf-on-color);
    cursor: pointer;
  }
}

.mic svg[b-qifbz75a8f] {
  width: 1.3rem;
  height: 1.3rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

html.yf-speech .compose .mic.listening[b-qifbz75a8f] {
  background: var(--yf-danger);
  border-color: var(--yf-danger);
  color: var(--yf-on-color);
  animation: mic-pulse-b-qifbz75a8f 1.2s ease-in-out infinite;
}

@keyframes mic-pulse-b-qifbz75a8f {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--yf-danger) 45%, transparent); }
  50% { box-shadow: 0 0 0 .45rem transparent; }
}

@media (prefers-reduced-motion: reduce) {
  html.yf-speech .compose .mic.listening[b-qifbz75a8f] { animation: none; }
}
/* /Components/Pages/Download.razor.rz.scp.css */
/* Scoped to Download.razor, a copy of Get.razor.css. Brand variables are on :root; .mk-btn is in app.css. */

.gt[b-mbnojouwp1] {
    max-width: 36rem;
    margin: 0 auto;
    padding: 3.5rem 1.5rem 3rem;
    text-align: center;
}

.gt h1[b-mbnojouwp1] {
    margin: 0 0 .75rem;
    font-size: clamp(1.9rem, 4vw, 2.6rem);
    font-weight: 700;
    color: var(--brand-blue-fg);
}

.gt-lede[b-mbnojouwp1] {
    margin: 0 0 2rem;
    font-size: 1.1rem;
    line-height: 1.6;
}

.gt-code-label[b-mbnojouwp1] {
    margin: 0;
    font-size: .9rem;
    color: var(--yf-muted);
}

.gt-code[b-mbnojouwp1] {
    margin: .25rem 0 2rem;
    font-family: Consolas, "Courier New", monospace;
    font-size: 2rem;
    font-weight: 700;
    letter-spacing: .12em;
    color: var(--brand-blue-fg);
}

.gt-btn[b-mbnojouwp1] {
    font-size: 1.2rem;
    padding: .9rem 2.2rem;
}

.gt-steps[b-mbnojouwp1] {
    margin: 2.5rem auto 1.5rem;
    padding-left: 1.4rem;
    text-align: left;
    line-height: 1.7;
}

.gt-small[b-mbnojouwp1] {
    font-size: .85rem;
    color: var(--yf-muted);
}
/* /Components/Pages/DownloadShop.razor.rz.scp.css */
/* Scoped to DownloadShop.razor. Started as a copy of Get.razor.css (the customer page), but this
   page is in the tech app, so it uses the full content width and reads left-aligned like the other
   tech pages (owner, 2026-10-07; was a centred 36rem column). */

.gt[b-dlnyw2m5rg] {
    padding: 0 0 2rem;
}

.gt h1[b-dlnyw2m5rg] {
    color: var(--brand-blue-fg);
}

.gt-lede[b-dlnyw2m5rg] {
    margin: 0 0 1.25rem;
    font-size: 1.05rem;
    line-height: 1.6;
}

.gt-code-label[b-dlnyw2m5rg] {
    margin: 0;
    font-size: .9rem;
    color: var(--yf-muted);
}

.gt-code[b-dlnyw2m5rg] {
    margin: .25rem 0 1.5rem;
    font-family: Consolas, "Courier New", monospace;
    font-size: 2rem;
    font-weight: 700;
    letter-spacing: .12em;
    color: var(--brand-blue-fg);
}

.gt-btn[b-dlnyw2m5rg] {
    font-size: 1.05rem;
    max-width: 100%;
    overflow-wrap: anywhere;
}

.gt-steps[b-dlnyw2m5rg] {
    margin: 0 0 1rem;
    padding-left: 1.4rem;
    line-height: 1.7;
}

.gt-small[b-dlnyw2m5rg] {
    font-size: .85rem;
    color: var(--yf-muted);
}

/* The three installation paths stacked, left-aligned, at twice the old 36rem column
   (owner, 2026-10-08). */
.gt-paths[b-dlnyw2m5rg] {
    display: flex;
    flex-direction: column;
    gap: 1.25rem;
    max-width: 72rem;
    margin: 0 0 1.5rem;
}

/* One block per installation path. */
.gt-path[b-dlnyw2m5rg] {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    padding: 1.25rem 1.5rem 1.5rem;
    border: 1px solid var(--yf-border);
    border-radius: 8px;
}

.gt-path h2[b-dlnyw2m5rg] {
    margin: 0 0 .5rem;
    font-size: 1.25rem;
    font-weight: 700;
    color: var(--brand-blue-fg);
}

.gt-path p[b-dlnyw2m5rg] {
    margin: 0 0 1rem;
    line-height: 1.6;
}

.gt-form[b-dlnyw2m5rg] {
    align-self: stretch;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: .5rem;
}

/* As wide as the longest customer name, not the whole box (owner, 2026-10-08). */
.gt-form select[b-dlnyw2m5rg] {
    width: auto;
    max-width: 100%;
    margin-bottom: .5rem;
}

/* The link under each download, small, with a copy button (js/copy-link.js). */
.gt-url[b-dlnyw2m5rg] {
    display: flex;
    align-items: center;
    gap: .35rem;
    margin-top: .75rem;
    max-width: 100%;
}

.gt-url code[b-dlnyw2m5rg] {
    font-size: .8rem;
    color: var(--yf-muted);
    background: none;
    padding: 0;
    overflow-wrap: anywhere;
}

.gt-url code.gt-url-empty[b-dlnyw2m5rg] { font-style: italic; }

.gt-copy[b-dlnyw2m5rg] {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.6rem;
    height: 1.6rem;
    padding: 0;
    border: 1px solid var(--yf-border);
    border-radius: .25rem;
    background: var(--bs-body-bg);
    color: var(--yf-muted);
    cursor: pointer;
}

.gt-copy:hover:not(:disabled)[b-dlnyw2m5rg] { color: var(--brand-blue-fg); border-color: var(--brand-blue); }
.gt-copy:disabled[b-dlnyw2m5rg] { opacity: .4; cursor: default; }
.gt-copy.copied[b-dlnyw2m5rg] { color: var(--yf-success-fg); border-color: var(--yf-success-fg); }

.gt-copy svg[b-dlnyw2m5rg] {
    width: .95rem;
    height: .95rem;
    fill: none;
    stroke: currentColor;
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
}

/* The installer's Installation Code boxes, ringed and numbered (owner, 2026-10-11). The
   screenshot is white whatever the theme: it is what the installer looks like. */
.gt-shot[b-dlnyw2m5rg] {
    margin: 0 0 1.5rem;
    max-width: 40rem;
}

.gt-shot svg[b-dlnyw2m5rg] {
    display: block;
    width: 100%;
    height: auto;
    border: 1px solid var(--yf-border);
    border-radius: .4rem;
    background: #ffffff;
}

.gt-shot-ring[b-dlnyw2m5rg] {
    fill: none;
    stroke: var(--brand-blue);
    stroke-width: 2.5;
}

.gt-shot-badge[b-dlnyw2m5rg] {
    fill: var(--brand-blue);
}

.gt-shot-num[b-dlnyw2m5rg] {
    fill: #ffffff;
    font-size: 11px;
    font-weight: 700;
    text-anchor: middle;
}

/* On the white screenshot in either theme, so a fixed dark ink rather than the body color. */
.gt-shot-label[b-dlnyw2m5rg] {
    fill: #1f2328;
    font-size: 13px;
    font-weight: 600;
}

.gt-shot figcaption[b-dlnyw2m5rg] {
    margin-top: .5rem;
    font-size: .9rem;
    color: var(--yf-muted);
}

/* /Components/Pages/Get.razor.rz.scp.css */
/* Scoped to Get.razor. Brand variables are on :root; .mk-btn is in app.css. */

.gt[b-lx2bh96ymq] {
    max-width: 36rem;
    margin: 0 auto;
    padding: 3.5rem 1.5rem 3rem;
    text-align: center;
}

.gt h1[b-lx2bh96ymq] {
    margin: 0 0 .75rem;
    font-size: clamp(1.9rem, 4vw, 2.6rem);
    font-weight: 700;
    color: var(--brand-blue-fg);
}

.gt-lede[b-lx2bh96ymq] {
    margin: 0 0 2rem;
    font-size: 1.1rem;
    line-height: 1.6;
}

.gt-code-label[b-lx2bh96ymq] {
    margin: 0;
    font-size: .9rem;
    color: var(--yf-muted);
}

.gt-code[b-lx2bh96ymq] {
    margin: .25rem 0 2rem;
    font-family: Consolas, "Courier New", monospace;
    font-size: 2rem;
    font-weight: 700;
    letter-spacing: .12em;
    color: var(--brand-blue-fg);
}

.gt-btn[b-lx2bh96ymq] {
    font-size: 1.2rem;
    padding: .9rem 2.2rem;
}

.gt-steps[b-lx2bh96ymq] {
    margin: 2.5rem auto 1.5rem;
    padding-left: 1.4rem;
    text-align: left;
    line-height: 1.7;
}

.gt-small[b-lx2bh96ymq] {
    font-size: .85rem;
    color: var(--yf-muted);
}
/* /Components/Pages/Legal.razor.rz.scp.css */
/* /terms and /privacy. ::deep because the text is rendered Markdown, not this component's markup. */

.legal[b-b3w3seiswb] {
    max-width: 46rem;
    margin: 0 auto;
    padding: 2.5rem 1.5rem 3rem;
    line-height: 1.65;
}

.legal[b-b3w3seiswb]  h1 {
    margin: 0 0 1rem;
    font-size: clamp(1.7rem, 3.5vw, 2.2rem);
    color: var(--brand-blue-fg);
}

.legal[b-b3w3seiswb]  h2 {
    margin: 2rem 0 .6rem;
    font-size: 1.25rem;
    color: var(--brand-blue-fg);
}

.legal[b-b3w3seiswb]  ul { padding-left: 1.3rem; }

.legal[b-b3w3seiswb]  li { margin-bottom: .35rem; }

.legal-draft[b-b3w3seiswb] {
    margin: 0 0 1.5rem;
    padding: .75rem 1rem;
    border-left: 4px solid var(--brand-orange, var(--brand-orange));
    background: var(--bs-body-bg);
    font-weight: 600;
}

.legal-notice[b-b3w3seiswb] {
    margin: 0 0 1.5rem;
    padding: .75rem 1rem;
    border-left: 4px solid var(--brand-blue, var(--brand-blue));
    background: var(--bs-body-bg);
}

.legal-meta[b-b3w3seiswb] {
    margin-top: 2.5rem;
    padding-top: 1rem;
    border-top: 1px solid var(--yf-border);
    font-size: .9rem;
    color: var(--yf-muted);
    display: flex;
    gap: 1rem;
    flex-wrap: wrap;
}

.legal-tag[b-b3w3seiswb] {
    margin-left: .4rem;
    padding: .05rem .4rem;
    border-radius: .3rem;
    background: var(--bs-body-bg);
    font-size: .8rem;
}

.legal-versions[b-b3w3seiswb] {
    width: 100%;
    border-collapse: collapse;
}

.legal-versions th[b-b3w3seiswb],
.legal-versions td[b-b3w3seiswb] {
    text-align: left;
    vertical-align: top;
    padding: .5rem .6rem;
    border-bottom: 1px solid var(--yf-border);
}

.legal[b-b3w3seiswb]  table {
    width: 100%;
    border-collapse: collapse;
    margin: 1rem 0;
}

.legal[b-b3w3seiswb]  th,
.legal[b-b3w3seiswb]  td {
    text-align: left;
    vertical-align: top;
    padding: .45rem .6rem;
    border: 1px solid var(--yf-border);
}
/* /Components/Pages/LegalAccept.razor.rz.scp.css */
.legal-accept[b-w5ja664inn] {
    max-width: 36rem;
}

.legal-accept-list[b-w5ja664inn] {
    padding-left: 1.2rem;
    margin: 1rem 0 1.5rem;
}

.legal-accept-list li[b-w5ja664inn] {
    margin-bottom: .75rem;
}

.legal-accept-list .signin-note[b-w5ja664inn] {
    display: block;
    margin: .15rem 0 0;
}

.legal-accept-check[b-w5ja664inn] {
    display: flex;
    gap: .6rem;
    align-items: flex-start;
    margin-bottom: 1rem;
}

.legal-accept-check[b-w5ja664inn]  input[type="checkbox"] {
    width: auto;
    margin-top: .25rem;
}

.legal-accept-signout button[b-w5ja664inn] {
    width: auto !important;
    background: none !important;
    border: none !important;
    color: var(--brand-blue, var(--brand-blue-fg)) !important;
    text-decoration: underline;
    padding: 0 !important;
    cursor: pointer;
}

.legal-accept-check[b-w5ja664inn] {
    font-weight: normal;
}
/* /Components/Pages/MachineDetailPage.razor.rz.scp.css */
/* The Connections preview's row actions: Report and Delete, spaced with a dot between two, as on
   the machine's full Connections page (Connections.razor.css). */
.acts[b-5z8d7nqh93] {
    white-space: nowrap;
    text-align: right;
}

.act[b-5z8d7nqh93] {
    display: inline-flex;
    align-items: center;
}

.act + .act[b-5z8d7nqh93]::before {
    content: "·";
    margin: 0 .6rem;
    color: var(--yf-muted);
}
/* /Components/Pages/Machines.razor.rz.scp.css */
/* The Machines page: a copy of the Customers page's rules (Customers.razor.css), so the two
   lists look and behave alike. 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-0j13mlxa4u] {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin-bottom: 0.75rem;
}

.cust-search[b-0j13mlxa4u] {
    flex: 0 1 22rem;
    padding: 0.4rem 0.6rem;
    font-size: 1rem;
    border: 1px solid var(--yf-border);
    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-0j13mlxa4u] {
    display: inline-block;
    min-width: 1.5rem;
    padding: 0 0.4rem;
    border-radius: 1rem;
    background: var(--bs-body-bg);
    color: var(--yf-muted);
    font-size: 0.8rem;
    text-align: center;
}

.cust-tools .edit-link[b-0j13mlxa4u] {
    margin-left: auto;
    font-size: 0.9rem;
}

.cust-scroll[b-0j13mlxa4u] {
    max-height: 32rem;
    overflow-y: auto;
    border: 1px solid var(--yf-border);
    border-radius: 0.25rem;
}

.cust[b-0j13mlxa4u] {
    width: 100%;
    border-collapse: collapse;
}

.cust th[b-0j13mlxa4u],
.cust td[b-0j13mlxa4u] {
    text-align: left;
    padding: 0.4rem 0.75rem;
    border-bottom: 1px solid var(--yf-border);
    vertical-align: middle;
    white-space: nowrap;
}

.cust th[b-0j13mlxa4u] {
    position: sticky;
    top: 0;
    background: var(--bs-body-bg);
    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-0j13mlxa4u] {
    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: var(--yf-muted);
    text-align: inherit;
    cursor: pointer;
}

.cust th .sort:hover[b-0j13mlxa4u] {
    color: var(--bs-body-color);
}

.cust th .arrow[b-0j13mlxa4u] {
    /* 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-0j13mlxa4u],
.cust td.num[b-0j13mlxa4u] {
    text-align: center;
}

.cust tr.inactive td[b-0j13mlxa4u] {
    color: var(--yf-muted);
}

/* .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 machines 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-0j13mlxa4u] {
    color: var(--yf-muted);
}

.cust-tools .show-off[b-0j13mlxa4u] {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    font-size: .9rem;
}

.cust-tools .show-off input[b-0j13mlxa4u] {
    width: auto;
    margin: 0;
}
/* /Components/Pages/PCScan.razor.rz.scp.css */
/* Scoped to PCScan.razor. Shares the .gt-* look with Get.razor, copied rather than shared
   because scoped CSS does not cross components. */

.gt[b-jk4y785431] {
    max-width: 36rem;
    margin: 0 auto;
    padding: 3.5rem 1.5rem 3rem;
    text-align: center;
}

.gt h1[b-jk4y785431] {
    margin: 0 0 .75rem;
    font-size: clamp(1.9rem, 4vw, 2.6rem);
    font-weight: 700;
    color: var(--brand-blue-fg);
}

.gt-lede[b-jk4y785431] {
    margin: 0 0 2rem;
    font-size: 1.1rem;
    line-height: 1.6;
}

.qd-form[b-jk4y785431] {
    display: flex;
    flex-wrap: wrap;
    gap: .75rem;
    justify-content: center;
}

.qd-email[b-jk4y785431] {
    flex: 1 1 16rem;
    max-width: 22rem;
    padding: .8rem 1rem;
    font-size: 1.1rem;
    border: 2px solid var(--yf-border);
    border-radius: 7px;
}

.qd-email:focus[b-jk4y785431] {
    outline: none;
    border-color: var(--brand-blue);
}

.gt-btn[b-jk4y785431] {
    font-size: 1.2rem;
    padding: .9rem 2.2rem;
    border: 0;
    cursor: pointer;
}

.gt-steps[b-jk4y785431] {
    margin: 2.5rem auto 1.5rem;
    padding-left: 1.4rem;
    text-align: left;
    line-height: 1.7;
}

.gt-small[b-jk4y785431] {
    font-size: .85rem;
    color: var(--yf-muted);
}

/* The install card's "welcome back" list of earlier scans (install-hint.js, migration 0004). */
.qd-past[b-jk4y785431] {
    list-style: none;
    margin: 0 auto 1.5rem;
    padding: 0;
    line-height: 2;
}

.qd-past li[b-jk4y785431] {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
    gap: .5rem;
}

/* ---- Sales page (PCScan Sales Page v1) -------------------------------------------------- */

.qd-hero[b-jk4y785431] { max-width: 40rem; }

.qd-only[b-jk4y785431] {
    margin: -1rem 0 2rem;
    font-size: 1.05rem;
    line-height: 1.6;
}

.qd-facts[b-jk4y785431] { margin-top: 1rem; }

.qd-band[b-jk4y785431] {
    max-width: 52rem;
    margin: 0 auto;
    padding: 2.5rem 1.5rem;
    line-height: 1.6;
}

/* Full-width tint, content in the same column as the plain bands. */
.qd-alt[b-jk4y785431] {
    max-width: none;
    background: var(--bs-body-bg);
    padding-left: max(1.5rem, calc((100% - 49rem) / 2));
    padding-right: max(1.5rem, calc((100% - 49rem) / 2));
}

.qd-band h2[b-jk4y785431] {
    margin: 0 0 1rem;
    font-size: 1.5rem;
    color: var(--brand-blue-fg);
}

.qd-band p[b-jk4y785431] { margin: 0 0 1rem; }

.qd-how[b-jk4y785431] {
    padding-left: 1.4rem;
    margin: 0;
}

.qd-how li[b-jk4y785431] { margin-bottom: .5rem; }

.qd-cols[b-jk4y785431] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
    gap: 2rem;
}

.qd-cols ul[b-jk4y785431] { padding-left: 1.2rem; margin: 0 0 1rem; }

.qd-never[b-jk4y785431] { list-style: none; padding-left: 0 !important; }

.qd-never li[b-jk4y785431]::before {
    content: "\2715";
    color: var(--yf-danger-fg);
    font-weight: 700;
    margin-right: .5rem;
}

.qd-faq dt[b-jk4y785431] {
    margin-top: 1.1rem;
    font-weight: 700;
}

.qd-faq dd[b-jk4y785431] { margin: .25rem 0 0; }

.qd-close[b-jk4y785431] { text-align: center; }

.qd-notwin[b-jk4y785431] {
    margin: 0 0 1rem;
    font-size: 1.05rem;
}
/* /Components/Pages/PCScanConfirm.razor.rz.scp.css */
/* Scoped to PCScanConfirm.razor. Same look as PCScan.razor and PCScanDone.razor. */

.gt[b-8f4iaxoc0g] {
    max-width: 36rem;
    margin: 0 auto;
    padding: 3.5rem 1.5rem 3rem;
    text-align: center;
}

.gt h1[b-8f4iaxoc0g] {
    margin: 0 0 .75rem;
    font-size: clamp(1.9rem, 4vw, 2.6rem);
    font-weight: 700;
    color: var(--brand-blue-fg);
}

.gt-lede[b-8f4iaxoc0g] {
    margin: 0 0 2rem;
    font-size: 1.1rem;
    line-height: 1.6;
}

.gt-btn[b-8f4iaxoc0g] {
    font-size: 1.2rem;
    padding: .9rem 2.2rem;
}

.gt-small[b-8f4iaxoc0g] {
    font-size: .85rem;
    color: var(--yf-muted);
}
/* /Components/Pages/PCScanDone.razor.rz.scp.css */
/* Scoped to PCScanDone.razor. Same look as PCScan.razor. */

.gt[b-65b4kkg62l] {
    max-width: 36rem;
    margin: 0 auto;
    padding: 3.5rem 1.5rem 3rem;
    text-align: center;
}

.gt h1[b-65b4kkg62l] {
    margin: 0 0 .75rem;
    font-size: clamp(1.9rem, 4vw, 2.6rem);
    font-weight: 700;
    color: var(--brand-blue-fg);
}

.gt-lede[b-65b4kkg62l] {
    margin: 0 0 2rem;
    font-size: 1.1rem;
    line-height: 1.6;
}

.gt-btn[b-65b4kkg62l] {
    font-size: 1.2rem;
    padding: .9rem 2.2rem;
}

.gt-small[b-65b4kkg62l] {
    font-size: .85rem;
    color: var(--yf-muted);
}

.gt-detail[b-65b4kkg62l] {
    white-space: pre-wrap;
    margin-bottom: 2rem;
}
/* /Components/Pages/PCScanEmailInUse.razor.rz.scp.css */
/* Scoped to PCScanEmailInUse.razor. Same look as PCScan.razor, PCScanDone.razor and PCScanInstalled.razor. */

.gt[b-6upui2m88v] {
    max-width: 36rem;
    margin: 0 auto;
    padding: 3.5rem 1.5rem 3rem;
    text-align: center;
}

.gt h1[b-6upui2m88v] {
    margin: 0 0 .75rem;
    font-size: clamp(1.9rem, 4vw, 2.6rem);
    font-weight: 700;
    color: var(--brand-blue-fg);
}

.gt-lede[b-6upui2m88v] {
    margin: 0 0 2rem;
    font-size: 1.1rem;
    line-height: 1.6;
}

.gt-btn[b-6upui2m88v] {
    font-size: 1.2rem;
    padding: .9rem 2.2rem;
}

.gt-small[b-6upui2m88v] {
    margin-top: 1.5rem;
    font-size: .85rem;
    color: var(--yf-muted);
}
/* /Components/Pages/PCScanInstalled.razor.rz.scp.css */
/* Scoped to PCScanInstalled.razor. Same look as PCScan.razor and PCScanDone.razor. */

.gt[b-a4h6qz9mp0] {
    max-width: 36rem;
    margin: 0 auto;
    padding: 3.5rem 1.5rem 3rem;
    text-align: center;
}

.gt h1[b-a4h6qz9mp0] {
    margin: 0 0 .75rem;
    font-size: clamp(1.9rem, 4vw, 2.6rem);
    font-weight: 700;
    color: var(--brand-blue-fg);
}

.gt-lede[b-a4h6qz9mp0] {
    margin: 0 0 2rem;
    font-size: 1.1rem;
    line-height: 1.6;
}

.gt-btn[b-a4h6qz9mp0] {
    font-size: 1.2rem;
    padding: .9rem 2.2rem;
}

.gt-secondary[b-a4h6qz9mp0] {
    background: var(--bs-body-bg);
    color: var(--brand-blue-fg);
    border: 2px solid var(--brand-blue);
}

.gt-or[b-a4h6qz9mp0] {
    margin: 1.75rem 0 2.5rem;
    font-size: 1rem;
    font-weight: 400;
    color: var(--yf-muted);
}

.gt-small[b-a4h6qz9mp0] {
    font-size: .85rem;
    color: var(--yf-muted);
}

/* An extra line's space under Reinstall on this computer. */
.gt-below-reinstall[b-a4h6qz9mp0] {
    margin-top: 1.5rem;
}
/* /Components/Pages/PCScanPriority.razor.rz.scp.css */
/* Scoped to PCScanPriority.razor. Same look as PCScan.razor and PCScanDone.razor. */

.gt[b-fixkhyk1qz] {
    max-width: 36rem;
    margin: 0 auto;
    padding: 3.5rem 1.5rem 3rem;
    text-align: center;
}

.gt h1[b-fixkhyk1qz] {
    margin: 0 0 .75rem;
    font-size: clamp(1.9rem, 4vw, 2.6rem);
    font-weight: 700;
    color: var(--brand-blue-fg);
}

.gt-lede[b-fixkhyk1qz] {
    margin: 0 0 2rem;
    font-size: 1.1rem;
    line-height: 1.6;
}

.gt-btn[b-fixkhyk1qz] {
    font-size: 1.2rem;
    padding: .9rem 2.2rem;
}

.gt-small[b-fixkhyk1qz] {
    font-size: .85rem;
    color: var(--yf-muted);
}
/* /Components/Pages/PCScanScansPanel.razor.rz.scp.css */
/* Scoped to PCScanScansPage.razor: each section in its own box, and the pager under the table. */

.qd-pager[b-d423jdoqvn] {
    display: flex;
    align-items: center;
    gap: .75rem;
    margin: .75rem 0 0;
}

@media (max-width: 600px) {
    .qd-pager[b-d423jdoqvn] {
        margin-top: 0;
    }
}

.pc-section[b-d423jdoqvn] {
    margin: 1.25rem 0;
    padding: 1.1rem 1.4rem 1.2rem;
    border: 1px solid var(--yf-border);
    border-radius: 12px;
    background: var(--bs-body-bg);
}

.pc-section > h2[b-d423jdoqvn] {
    margin: 0 0 .5rem;
}

.pc-section > :last-child[b-d423jdoqvn] {
    margin-bottom: 0;
}

/* A row's actions: View · Report · Abort · Delete, with the dot only between two of them. */
.acts[b-d423jdoqvn] {
    white-space: nowrap;
}

.act + .act[b-d423jdoqvn]::before {
    content: "·";
    margin: 0 .4rem;
    color: var(--yf-muted);
}
/* /Components/Pages/Settings/LegalDocumentsPage.razor.rz.scp.css */
.legal-docs tr.active td[b-4ibw32xlka] {
    background: var(--bs-body-bg);
}

.legal-inline[b-4ibw32xlka] {
    display: flex !important;
    align-items: baseline;
    gap: .5rem;
    flex-wrap: wrap;
}

.legal-inline input[type="checkbox"][b-4ibw32xlka] {
    display: inline-block !important;
    width: auto !important;
}

.prompt-edit textarea[b-4ibw32xlka],
.prompt-edit input:not([type="checkbox"])[b-4ibw32xlka] {
    display: block;
    width: 100%;
    margin-top: .3rem;
    padding: .45rem;
    border: 1px solid var(--yf-border);
    border-radius: .25rem;
}

.prompt-edit label[b-4ibw32xlka] {
    display: block;
    margin-top: 1rem;
    font-weight: 600;
}

.prompt-edit label .muted[b-4ibw32xlka] {
    font-weight: normal;
    font-size: .85rem;
    margin-left: .5rem;
}

.prompt-actions[b-4ibw32xlka] {
    display: flex;
    align-items: center;
    gap: .6rem;
    margin: 1rem 0 1.5rem;
    flex-wrap: wrap;
}

.prompt-actions button[b-4ibw32xlka],
.versions button[b-4ibw32xlka] {
    padding: .4rem .9rem;
    border: 1px solid var(--yf-border);
    border-radius: .25rem;
    background: var(--bs-body-bg);
    cursor: pointer;
}

.prompt-actions button.primary[b-4ibw32xlka],
.versions button.primary[b-4ibw32xlka] {
    border-color: var(--brand-blue);
    background: var(--brand-blue);
    color: var(--yf-on-color);
}

.prompt-actions button:disabled[b-4ibw32xlka],
.versions button:disabled[b-4ibw32xlka] {
    opacity: .5;
    cursor: default;
}

.versions[b-4ibw32xlka] {
    width: 100%;
    border-collapse: collapse;
    margin-bottom: 1.5rem;
}

.versions th[b-4ibw32xlka],
.versions td[b-4ibw32xlka] {
    text-align: left;
    vertical-align: top;
    padding: .45rem .6rem;
    border-bottom: 1px solid var(--yf-border);
}

.versions .by[b-4ibw32xlka] {
    font-size: .8rem;
    color: var(--yf-muted);
}

.versions pre[b-4ibw32xlka] {
    white-space: pre-wrap;
    max-height: 24rem;
    overflow: auto;
}

.row-actions[b-4ibw32xlka] {
    display: flex;
    flex-direction: column;
    gap: .3rem;
}
/* /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-dtqxojetfg] {
    margin: 0 0 1rem;
    padding: .75rem 1rem;
    border: 1px solid var(--yf-border);
    border-radius: .375rem;
    background: var(--bs-body-bg);
    max-width: 48rem;
}

.ep-pick[b-dtqxojetfg] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .5rem .75rem;
    margin-bottom: .75rem;
}

.ep-pick label[b-dtqxojetfg] {
    font-weight: 600;
}

.ep-status[b-dtqxojetfg] {
    font-size: .9rem;
    color: var(--yf-muted);
}

.ep-warn[b-dtqxojetfg] {
    color: var(--brand-orange);
}

.ep-form[b-dtqxojetfg] {
    width: 100%;
    border-collapse: collapse;
}

.ep-form td[b-dtqxojetfg] {
    padding: .25rem .5rem .25rem 0;
    vertical-align: middle;
}

.ep-key[b-dtqxojetfg] {
    width: 12rem;
    font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
    font-size: .85rem;
    white-space: nowrap;
}

.ep-form .setting-input[b-dtqxojetfg] {
    width: 100%;
    box-sizing: border-box;
}

.ep-actions[b-dtqxojetfg] {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    margin-top: .75rem;
}

/* Model.SupportsFiles (migration 0074). */
.ep-check[b-dtqxojetfg] {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    font-size: .9rem;
    cursor: pointer;
}

/* The bearer token row (migration 0086): Remove beside the box, the http warning under it. */
.ep-inline[b-dtqxojetfg] {
    margin-left: .5rem;
}

.ep-note[b-dtqxojetfg] {
    font-size: .85rem;
    margin-top: .25rem;
}
/* /Components/Pages/Settings/ServerActivity.razor.rz.scp.css */
/* A session row's actions: View, then Abort, spaced apart. */
.acts[b-14l8mtpn2o] {
    white-space: nowrap;
}

.act[b-14l8mtpn2o] {
    display: inline-flex;
    align-items: center;
    vertical-align: middle;
}

.act + .act[b-14l8mtpn2o] {
    margin-left: .6rem;
}
/* /Components/Pages/Settings/ServerSmtp.razor.rz.scp.css */
/* The View link and the Delete button beside the Smtp.LogEnabled checkbox. Authored in this
   file, so they carry this page's scope even though SettingsTable renders them. */
.smtp-log-links[b-llisxhdwym] {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .25rem .75rem;
    margin-left: .75rem;
    font-size: .9rem;
}
/* /Components/Pages/Settings/ServerSmtpLog.razor.rz.scp.css */
.smtp-log-bar[b-jtcdcx0c9j] {
    margin-bottom: .75rem;
}

/* Nine columns do not fit a phone: the table scrolls inside its box, the page does not. */
.smtp-log-scroll[b-jtcdcx0c9j] {
    overflow-x: auto;
    margin-bottom: 1rem;
}

.smtp-log[b-jtcdcx0c9j] {
    margin-bottom: 0;
    font-size: .875rem;
}

.smtp-log td[b-jtcdcx0c9j] {
    vertical-align: top;
}

.smtp-log .nowrap[b-jtcdcx0c9j] {
    white-space: nowrap;
}

.smtp-log .wrap[b-jtcdcx0c9j] {
    overflow-wrap: anywhere;
    min-width: 10rem;
}

/* The summary line and its raw log read as one entry: no rule between them. */
.smtp-log tr.smtp-summary td[b-jtcdcx0c9j] {
    border-bottom: 0;
    padding-bottom: .15rem;
}

.smtp-log tr.smtp-raw td[b-jtcdcx0c9j] {
    padding-top: 0;
    padding-bottom: 1rem;
}

/* Why it was not sent: the exception chain, one message per line. */
.smtp-detail[b-jtcdcx0c9j] {
    white-space: pre-line;
    color: var(--yf-danger-fg);
    margin-bottom: .35rem;
}

.smtp-log summary[b-jtcdcx0c9j] {
    cursor: pointer;
    font-size: .8rem;
    color: var(--yf-muted);
}

/* The conversation exactly as recorded. Scrolls sideways rather than wrapping, because a
   wrapped SMTP line reads as two. */
.smtp-transcript[b-jtcdcx0c9j] {
    margin: .35rem 0 0;
    padding: .6rem .75rem;
    max-height: 28rem;
    overflow: auto;
    background: var(--bs-body-bg);
    border: 1px solid var(--yf-border);
    border-radius: .25rem;
    font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
    font-size: .8rem;
    line-height: 1.35;
    white-space: pre;
}

.smtp-result[b-jtcdcx0c9j] {
    display: inline-block;
    padding: .05rem .5rem;
    border-radius: 1rem;
    font-size: .8rem;
    font-weight: 600;
    white-space: nowrap;
}

.smtp-result-sent[b-jtcdcx0c9j]       { background: var(--bs-body-bg); color: var(--yf-success-fg); }
.smtp-result-suppressed[b-jtcdcx0c9j] { background: var(--bs-body-bg); color: var(--yf-danger-fg); }
.smtp-result-notsent[b-jtcdcx0c9j]    { background: var(--bs-body-bg); color: var(--yf-danger-fg); }

.smtp-pager[b-jtcdcx0c9j] {
    display: flex;
    align-items: center;
    gap: .75rem;
    margin-bottom: 1.5rem;
}
/* /Components/Pages/Settings/ShopApprovalTables.razor.rz.scp.css */
/* The two approval queues under the Shops table (migration 0103). The look of ShopsTable.razor.css,
   copied for the reason that file gives, with two differences: the "What the check found" column
   wraps, because it is sentences, and a row's buttons sit side by side. */

.approvals-section[b-imeh9j8xrs] {
    margin-top: 2rem;
}

.approvals-section h2[b-imeh9j8xrs] {
    font-size: 1.15rem;
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.count[b-imeh9j8xrs] {
    display: inline-block;
    min-width: 1.5rem;
    padding: 0 0.4rem;
    border-radius: 1rem;
    background: var(--bs-body-bg);
    color: var(--yf-muted);
    font-size: 0.8rem;
    font-weight: normal;
    text-align: center;
}

.muted[b-imeh9j8xrs] {
    color: var(--yf-muted);
}

.approvals-scroll[b-imeh9j8xrs] {
    max-height: 32rem;
    overflow: auto;
    border: 1px solid var(--yf-border);
    border-radius: 0.25rem;
}

.approvals[b-imeh9j8xrs] {
    width: 100%;
    border-collapse: collapse;
}

.approvals th[b-imeh9j8xrs],
.approvals td[b-imeh9j8xrs] {
    text-align: left;
    padding: 0.4rem 0.75rem;
    border-bottom: 1px solid var(--yf-border);
    vertical-align: top;
    white-space: nowrap;
}

.approvals th[b-imeh9j8xrs] {
    position: sticky;
    top: 0;
    background: var(--bs-body-bg);
    z-index: 1;
    font-size: 0.8rem;
    font-weight: normal;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--yf-muted);
}

.approvals td.code[b-imeh9j8xrs] {
    font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
    letter-spacing: 0.05em;
}

.approvals td.found[b-imeh9j8xrs] {
    white-space: normal;
    min-width: 22rem;
    max-width: 40rem;
}

.approvals td.found summary[b-imeh9j8xrs] {
    cursor: pointer;
}

.approvals td.actions[b-imeh9j8xrs] {
    display: flex;
    gap: 0.4rem;
    flex-wrap: nowrap;
}

.checks[b-imeh9j8xrs] {
    list-style: none;
    margin: 0.4rem 0 0;
    padding: 0;
}

.checks li[b-imeh9j8xrs] {
    margin-bottom: 0.3rem;
}

.checks .mark[b-imeh9j8xrs] {
    display: inline-block;
    width: 1.1rem;
    font-weight: 700;
}

.checks li.pass .mark[b-imeh9j8xrs] {
    color: var(--yf-success-fg);
}

.checks li.fail .mark[b-imeh9j8xrs] {
    color: var(--yf-danger-fg);
}
/* /Components/Pages/Settings/ShopEditor.razor.rz.scp.css */
/* One rule, and the shortness is deliberate.

   This form is meant to look exactly like Settings/Shop.razor, the page a shop's own
   administrator uses -- same fields, same order, same plain fieldsets. `.shop-section` is
   styled nowhere in the solution, so that page renders with browser defaults, and styling it
   here would style only this copy and make the two drift apart. If those fieldsets are worth
   dressing up, it belongs in app.css where both pages get it.

   The banner is the exception because it has no counterpart over there: it is the line saying
   whose shop this is, and it is the one thing on the page that must not read as ordinary
   prose. Blue rather than amber -- nothing is wrong, and a warning colour on every visit is a
   warning colour nobody reads by the third one. */

.op-banner[b-kkm5bsjhwg] {
    padding: 0.6rem 0.75rem;
    margin: 0 0 1.25rem;
    border-left: 3px solid var(--brand-blue);
    border-radius: 0.25rem;
    background-color: var(--bs-body-bg);
    color: var(--brand-blue-fg);
}

.op-banner a[b-kkm5bsjhwg] {
    color: inherit;
}

/* The prices' history under their table (ShopPricesEditor), closed until asked for. ::deep
   because the table is the child component's markup. */
[b-kkm5bsjhwg] .price-history {
    margin: .5rem 0 1.5rem;
}

[b-kkm5bsjhwg] .price-history > summary {
    cursor: pointer;
    color: var(--yf-muted);
}

/* PCScan and DailyDelta are one-row sections (owner, 2026-10-11): no rule under the lone row.
   ::deep because the cells are SettingRow's markup; tr covers the phone layout in app.css. */
.no-rule[b-kkm5bsjhwg]  td,
.no-rule[b-kkm5bsjhwg]  tr {
    border-bottom: none;
}

/* Inside Delete this shop's popup (ConfirmButton's .confirm-extra is a centred flex row): the
   counts above the Shop ID box, both left aligned, the box a narrow one. */
.shop-delete-confirm[b-kkm5bsjhwg] {
    text-align: left;
    width: 100%;
}

.shop-delete-confirm label[b-kkm5bsjhwg] {
    display: block;
}

.shop-delete-confirm input[b-kkm5bsjhwg] {
    width: 7rem;
    margin-top: .35rem;
    font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
}
/* /Components/Pages/Settings/ShopsTable.razor.rz.scp.css */
/* The operator's Shops list. Same shape as Customers.razor.css, which is the table this one
   is meant to look and behave like: 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.

   Copied rather than shared, matching what the solution already does. The two tables live in
   different sections behind different gates, and a shared stylesheet between them would be a
   coupling nobody asked for: the day the operator's table needs a column the customers' table
   does not, one of the two starts fighting the other. */

.shops-tools[b-nlezc9safj] {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin-bottom: 0.75rem;
}

.shops-search[b-nlezc9safj] {
    flex: 0 1 22rem;
    padding: 0.4rem 0.6rem;
    font-size: 1rem;
    border: 1px solid var(--yf-border);
    border-radius: 0.25rem;
}

/* Counts what is on screen, not what the server has, which is the number that matters while
   a search is narrowing. */
.count[b-nlezc9safj] {
    display: inline-block;
    min-width: 1.5rem;
    padding: 0 0.4rem;
    border-radius: 1rem;
    background: var(--bs-body-bg);
    color: var(--yf-muted);
    font-size: 0.8rem;
    text-align: center;
}

.shops-scroll[b-nlezc9safj] {
    max-height: 32rem;
    overflow-y: auto;
    border: 1px solid var(--yf-border);
    border-radius: 0.25rem;
}

.shops[b-nlezc9safj] {
    width: 100%;
    border-collapse: collapse;
}

.shops th[b-nlezc9safj],
.shops td[b-nlezc9safj] {
    text-align: left;
    padding: 0.4rem 0.75rem;
    border-bottom: 1px solid var(--yf-border);
    vertical-align: middle;
    white-space: nowrap;
}

.shops th[b-nlezc9safj] {
    position: sticky;
    top: 0;
    background: var(--bs-body-bg);
    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. */
.shops th .sort[b-nlezc9safj] {
    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: var(--yf-muted);
    text-align: inherit;
    cursor: pointer;
}

.shops th .sort:hover[b-nlezc9safj] {
    color: var(--bs-body-color);
}

.shops th .arrow[b-nlezc9safj] {
    /* 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;
}

.shops th.num[b-nlezc9safj],
.shops td.num[b-nlezc9safj] {
    text-align: center;
}

/* The installation code is read off one screen and typed into another, so it is set in a
   monospaced face here for the same reason it excludes 0, O, 1 and I in the first place. */
.shops td.code[b-nlezc9safj] {
    font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
    letter-spacing: 0.05em;
}

.shops tr.inactive td[b-nlezc9safj] {
    color: var(--yf-muted);
}

/* YouFixIt.ai's own row. Not tag-on, which is green and already means "in service" two columns
   along -- this says "whose server this is", which is a different kind of fact. */
.shops .tag-op[b-nlezc9safj] {
    margin-left: 0.5rem;
    background-color: var(--bs-body-bg);
    color: var(--brand-blue-fg);
}

/* .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. Given here so that "No shops 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 everywhere else. */
.shops .muted[b-nlezc9safj] {
    color: var(--yf-muted);
}
/* /Components/Pages/Settings/SystemPrompts.razor.rz.scp.css */
.prompt-edit[b-uuraasa7um] {
  max-width: 64rem;
}

.prompt-edit label[b-uuraasa7um] {
  display: block;
  margin-top: 1rem;
  font-weight: 600;
}

.prompt-edit label .muted[b-uuraasa7um] {
  font-weight: normal;
  font-size: .85rem;
  margin-left: .5rem;
}

.prompt-edit textarea[b-uuraasa7um],
.prompt-edit input[b-uuraasa7um] {
  display: block;
  width: 100%;
  margin-top: .3rem;
  padding: .45rem;
  border: 1px solid var(--yf-border);
  border-radius: .25rem;
  font-weight: normal;
}

.prompt-edit textarea[b-uuraasa7um] {
  font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
  font-size: .85rem;
  resize: vertical;
}

.prompt-actions[b-uuraasa7um] {
  display: flex;
  align-items: center;
  gap: .6rem;
  margin: 1rem 0 1.5rem;
}

.prompt-actions button[b-uuraasa7um],
.versions button[b-uuraasa7um] {
  padding: .4rem .9rem;
  border: 1px solid var(--yf-border);
  border-radius: .25rem;
  background: var(--bs-body-bg);
  cursor: pointer;
}

.prompt-actions button.primary[b-uuraasa7um],
.versions button.primary[b-uuraasa7um] {
  border-color: var(--brand-blue);
  background: var(--brand-blue);
  color: var(--yf-on-color);
}

.prompt-actions button:disabled[b-uuraasa7um],
.versions button:disabled[b-uuraasa7um] {
  opacity: .5;
  cursor: default;
}

.versions[b-uuraasa7um] {
  border-collapse: collapse;
  width: 100%;
  max-width: 64rem;
  font-size: .875rem;
}

.versions th[b-uuraasa7um],
.versions td[b-uuraasa7um] {
  border-bottom: 1px solid var(--yf-border);
  padding: .4rem .6rem;
  text-align: left;
  vertical-align: top;
}

.versions tr.active td[b-uuraasa7um] {
  background: var(--bs-body-bg);
}

.notes-cell[b-uuraasa7um] {
  overflow-wrap: anywhere;
}

.notes-cell summary[b-uuraasa7um] {
  cursor: pointer;
  color: var(--brand-blue-fg);
  font-size: .8rem;
  margin-top: .25rem;
}

.notes-cell pre[b-uuraasa7um] {
  white-space: pre-wrap;
  background: var(--bs-body-bg);
  border: 1px solid var(--yf-border);
  padding: .5rem;
  max-height: 24rem;
  overflow-y: auto;
  font-size: .75rem;
}

.raw-label[b-uuraasa7um] {
  display: block;
  font-size: .75rem;
  font-weight: 600;
  margin-top: .5rem;
  color: var(--yf-muted);
}

.muted[b-uuraasa7um] {
  color: var(--yf-muted);
}

.notice[b-uuraasa7um] {
  padding: .6rem .75rem;
  border-radius: .25rem;
}

.notice-ok[b-uuraasa7um] {
  background-color: var(--bs-body-bg);
  color: var(--yf-success-fg);
}

.notice-error[b-uuraasa7um] {
  background-color: var(--bs-body-bg);
  color: var(--yf-danger-fg);
}

.by[b-uuraasa7um] {
  font-size: .75rem;
  color: var(--yf-muted);
}

.versions .actions-cell[b-uuraasa7um] {
  width: 1%;
  white-space: nowrap;
}

.row-actions[b-uuraasa7um] {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: .4rem;
  min-width: 7.5rem;
}

.row-actions strong[b-uuraasa7um] {
  text-align: center;
  padding: .4rem 0;
}

.versions .confirm[b-uuraasa7um] {
  font-size: .8rem;
  text-align: center;
}

.versions button.danger[b-uuraasa7um] {
  border-color: var(--yf-danger);
  background: var(--yf-danger);
  color: var(--yf-on-color);
}
/* /Components/Pages/Settings/ThemeColorEditor.razor.rz.scp.css */
/* The color editor (ThemeColorEditor.razor). Its own colors are theme variables like everything
   else, so it reads in either scheme. */

.tc-heading[b-3i0x2zjd3y] { margin-top: 2rem; }

.tc-bar[b-3i0x2zjd3y] {
    display: flex;
    flex-wrap: wrap;
    gap: .75rem;
    align-items: center;
    margin-bottom: .5rem;
}

.tc-tabs[b-3i0x2zjd3y] { display: flex; gap: .25rem; }

.tc-tab[b-3i0x2zjd3y] {
    padding: .35rem .9rem;
    border: 1px solid var(--yf-border);
    border-radius: .3rem;
    background: var(--bs-body-bg);
    color: var(--bs-body-color);
    cursor: pointer;
}

.tc-tab.active[b-3i0x2zjd3y] {
    background: var(--brand-blue);
    border-color: var(--brand-blue);
    color: var(--yf-on-color);
}

.tc-filter[b-3i0x2zjd3y] {
    flex: 1 1 16rem;
    max-width: 24rem;
    padding: .35rem .6rem;
    border: 1px solid var(--yf-border);
    border-radius: .3rem;
    background: var(--bs-body-bg);
    color: var(--bs-body-color);
}

.tc-hint[b-3i0x2zjd3y] { font-size: .9rem; }

.tc-group[b-3i0x2zjd3y] {
    margin: 1.5rem 0 .4rem;
    font-size: 1.05rem;
}

.tc-table[b-3i0x2zjd3y] {
    width: 100%;
    border-collapse: collapse;
}

.tc-table td[b-3i0x2zjd3y] {
    padding: .3rem .5rem;
    border-bottom: 1px solid var(--yf-border);
    vertical-align: middle;
}

.tc-table tr.changed td[b-3i0x2zjd3y] { background: var(--bs-body-bg); }

.tc-swatch-cell[b-3i0x2zjd3y] { width: 2.5rem; }

.tc-swatch[b-3i0x2zjd3y] {
    display: inline-block;
    width: 1.6rem;
    height: 1.6rem;
    vertical-align: middle;
    border: 1px solid var(--yf-muted);
    border-radius: .25rem;
    /* A see-through color over a checkerboard, so its transparency shows. The color itself is an
       inset shadow (set inline), which paints above the background image. */
    background-image: linear-gradient(45deg, var(--bs-body-bg) 25%, transparent 25%, transparent 75%, var(--bs-body-bg) 75%),
                      linear-gradient(45deg, var(--bs-body-bg) 25%, transparent 25%, transparent 75%, var(--bs-body-bg) 75%);
    background-size: 8px 8px;
    background-position: 0 0, 4px 4px;
}

.tc-name[b-3i0x2zjd3y] { min-width: 12rem; }

.tc-label[b-3i0x2zjd3y] { display: block; }

.tc-usage[b-3i0x2zjd3y] {
    display: block;
    font-size: .78rem;
    color: var(--yf-muted);
    overflow-wrap: anywhere;
}

.tc-edit[b-3i0x2zjd3y] {
    width: 1%;
    white-space: nowrap;
}

.tc-edit input[type="color"][b-3i0x2zjd3y] {
    width: 2.4rem;
    height: 2rem;
    padding: 0 .1rem;
    vertical-align: middle;
    border: 1px solid var(--yf-border);
    border-radius: .25rem;
    background: var(--bs-body-bg);
    cursor: pointer;
}

.tc-value[b-3i0x2zjd3y] {
    width: 13rem;
    margin-left: .35rem;
    padding: .3rem .5rem;
    font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
    font-size: .85rem;
    vertical-align: middle;
    border: 1px solid var(--yf-border);
    border-radius: .25rem;
    background: var(--bs-body-bg);
    color: var(--bs-body-color);
}

.tc-reset[b-3i0x2zjd3y] {
    margin-left: .35rem;
    padding: .25rem .6rem;
    border: 1px solid var(--yf-border);
    border-radius: .25rem;
    background: var(--bs-body-bg);
    color: var(--bs-body-color);
    cursor: pointer;
}

.tc-backdrop[b-3i0x2zjd3y] {
    position: fixed;
    inset: 0;
    z-index: 1040;
    background: var(--yf-shadow);
}

.tc-dialog[b-3i0x2zjd3y] {
    position: fixed;
    z-index: 1050;
    top: 10vh;
    left: 50%;
    transform: translateX(-50%);
    width: min(36rem, calc(100vw - 2rem));
    max-height: 80vh;
    overflow-y: auto;
    padding: 1.25rem 1.5rem;
    border-radius: .5rem;
    background: var(--bs-body-bg);
    color: var(--bs-body-color);
    box-shadow: 0 20px 45px var(--yf-shadow);
}

.tc-dialog h3[b-3i0x2zjd3y] {
    margin-top: 0;
    font-size: 1.15rem;
}

.tc-matches[b-3i0x2zjd3y] {
    max-height: 14rem;
    overflow-y: auto;
    padding-left: 1.2rem;
}

.tc-matches li[b-3i0x2zjd3y] { margin-bottom: .3rem; }

.tc-dialog-actions[b-3i0x2zjd3y] {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    margin-top: 1rem;
}

@media (max-width: 640px) {
    .tc-table tr[b-3i0x2zjd3y] { display: grid; grid-template-columns: 2.5rem 1fr; }
    .tc-edit[b-3i0x2zjd3y] { grid-column: 1 / -1; white-space: normal; }
    .tc-value[b-3i0x2zjd3y] { width: calc(100% - 3.2rem); }
}

.tc-new[b-3i0x2zjd3y] { border-style: dashed; }

.tc-delete[b-3i0x2zjd3y] {
    margin-left: .35rem;
    padding: .15rem .6rem;
    border: 1px solid var(--yf-danger-fg);
    border-radius: .25rem;
    background: transparent;
    color: var(--yf-danger-fg);
    cursor: pointer;
}

.tc-delete:disabled[b-3i0x2zjd3y] { opacity: .5; cursor: not-allowed; }

.tc-export[b-3i0x2zjd3y] {
    margin-left: .35rem;
    padding: .15rem .6rem;
    border: 1px solid var(--brand-blue);
    border-radius: .25rem;
    background: transparent;
    color: var(--brand-blue-fg);
    cursor: pointer;
}

.tc-export:disabled[b-3i0x2zjd3y] { opacity: .5; cursor: not-allowed; }

/* Import scheme…: a label that looks like the tab buttons, with the file input inside it
   hidden but still reachable from the keyboard. InputFile is a component, so ::deep. */
.tc-import[b-3i0x2zjd3y] {
    position: relative;
    margin: 0;
    display: inline-flex;
    align-items: center;
}

/* Buttons and a label take different fonts by default: one font for all of the tabs. */
.tc-tab[b-3i0x2zjd3y] {
    font-family: inherit;
    font-size: .9rem;
    line-height: 1.4;
}

.tc-import:focus-within[b-3i0x2zjd3y] {
    outline: 2px solid var(--brand-blue);
    outline-offset: 2px;
}

.tc-import.disabled[b-3i0x2zjd3y] { opacity: .5; cursor: not-allowed; }

.tc-import[b-3i0x2zjd3y]  input[type="file"] {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    overflow: hidden;
}

.tc-newform[b-3i0x2zjd3y] {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem .75rem;
    align-items: end;
    margin: .5rem 0 1rem;
    padding: .75rem 1rem;
    border: 1px solid var(--yf-border);
    border-radius: .4rem;
}

.tc-newform label[b-3i0x2zjd3y] {
    display: flex;
    flex-direction: column;
    gap: .2rem;
    font-size: .9rem;
}

.tc-newform input[b-3i0x2zjd3y],
.tc-newform select[b-3i0x2zjd3y] {
    padding: .3rem .5rem;
    border: 1px solid var(--yf-border);
    border-radius: .25rem;
    background: var(--yf-dropdown-bg);
    color: var(--bs-body-color);
}

.tc-newform .tc-usage[b-3i0x2zjd3y] { flex-basis: 100%; }
/* /Components/Pages/ShopConnections.razor.rz.scp.css */
/* A row's actions on Connections: View · Report · Delete, spaced apart with a dot between two. */
.acts[b-b9pfhcdxfv] {
    white-space: nowrap;
}

.act[b-b9pfhcdxfv] {
    display: inline-flex;
    align-items: center;
}

.act + .act[b-b9pfhcdxfv]::before {
    content: "·";
    margin: 0 .6rem;
    color: var(--yf-muted);
}

/* Delete All, above the Recent Connections table. */
.delete-all[b-b9pfhcdxfv] {
    margin: 0 0 .5rem;
}
/* /Components/Pages/Signup.razor.rz.scp.css */
/* The agreement checkbox (Legal Documents v1, section 5). .signin makes every input full width. */
.signup-agree[b-h6xt60h4dg] {
    display: flex !important;
    gap: .6rem;
    align-items: flex-start;
    font-weight: normal;
    margin: 1rem 0;
}

.signup-agree[b-h6xt60h4dg]  input[type="checkbox"] {
    width: auto !important;
    margin-top: .25rem;
    flex: none;
}
/* /Components/Pages/TechnicianConnections.razor.rz.scp.css */
/* One technician's connection history. The table itself is .techs, which app.css already
   styles for the technicians and machine-connection lists; only the pager is new. */

.pager[b-8dp52i2wn0] {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin-top: 0.75rem;
}

/* The same pill Customers.razor.css uses beside its table. Counting all the connections
   rather than the rows on screen, because the page number above it is the screen. */
.pager .count[b-8dp52i2wn0] {
    display: inline-block;
    padding: 0 0.5rem;
    border-radius: 1rem;
    background: var(--bs-body-bg);
    color: var(--yf-muted);
    font-size: 0.8rem;
}

/* Previous on the left, Next pushed to the right, the count between them: the two links
   never move, so the target stays put while the number in the middle changes. */
.pager .edit-link:last-child[b-8dp52i2wn0] {
    margin-left: auto;
}

/* .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 it is given here for the breadcrumb
   line under the heading. */
.muted[b-8dp52i2wn0] {
    color: var(--yf-muted);
}
/* /Components/Pages/TechnicianGroupEdit.razor.rz.scp.css */
.group-members td:first-child[b-ocwxkdhpib],
.group-members th:first-child[b-ocwxkdhpib] {
    text-align: center;
    width: 5rem;
}

.cust-tools[b-ocwxkdhpib] {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin-bottom: 0.5rem;
}

.cust-search[b-ocwxkdhpib] {
    min-width: 16rem;
}
/* /Components/Pages/TechnicianGroups.razor.rz.scp.css */
.group-new[b-ibqll5x8s7] {
    display: flex;
    gap: 0.5rem;
    align-items: center;
    flex-wrap: wrap;
    margin-bottom: 0.5rem;
}

.group-new input[b-ibqll5x8s7] {
    min-width: 16rem;
}
/* /Components/Pages/Tutorial.razor.rz.scp.css */
/* Scoped to Tutorial.razor. Nothing here is reused, so it stays with the page rather than
   growing app.css. The brand variables are on :root, which scoped CSS still inherits. */

h1[b-st14bttmvb] {
    color: var(--brand-blue-fg);
}

.tut-lede[b-st14bttmvb] {
    max-width: 44rem;
    margin-bottom: 2rem;
    font-size: 1.05rem;
    color: var(--yf-muted);
}

.tut-section[b-st14bttmvb] {
    max-width: 44rem;
    margin-bottom: 2.5rem;
}

.tut-section h2[b-st14bttmvb] {
    margin-bottom: .6rem;
    padding-bottom: .35rem;
    border-bottom: 2px solid var(--brand-orange);
    font-size: 1.2rem;
    font-weight: 600;
    color: var(--brand-blue-fg);
}

/* Shop -> Customer -> Machine -> Session. Indented one step per level, because the nesting IS
   the explanation: four bullets in a flat list would say four things sit side by side. */
.tut-chain[b-st14bttmvb] {
    margin: 0 0 1rem;
    padding: 0;
    list-style: none;
    counter-reset: chain;
}

.tut-chain li[b-st14bttmvb] {
    position: relative;
    margin: 0 0 .4rem;
    padding: .55rem .75rem .55rem 1.1rem;
    border-left: 3px solid var(--brand-orange);
    background: var(--bs-body-bg);
    border-radius: 0 6px 6px 0;
}

.tut-chain li:nth-child(2)[b-st14bttmvb] { margin-left: 1.25rem; }
.tut-chain li:nth-child(3)[b-st14bttmvb] { margin-left: 2.5rem; }
.tut-chain li:nth-child(4)[b-st14bttmvb] { margin-left: 3.75rem; }

.tut-chain strong[b-st14bttmvb] {
    display: block;
    color: var(--brand-blue-fg);
}

.tut-chain span[b-st14bttmvb] {
    color: var(--yf-muted);
}

.tut-steps[b-st14bttmvb] {
    margin: 0 0 1rem;
    padding-left: 1.25rem;
}

.tut-steps li[b-st14bttmvb],
.tut-list li[b-st14bttmvb] {
    margin-bottom: .5rem;
    line-height: 1.55;
}

.tut-list[b-st14bttmvb] {
    margin: 0 0 1rem;
    padding-left: 1.25rem;
}

.tut-list strong[b-st14bttmvb],
.tut-steps strong[b-st14bttmvb] {
    color: var(--brand-blue-fg);
}

/* The aside at the end of a section: true, useful, and not the point of the section. */
.tut-note[b-st14bttmvb] {
    margin: 0;
    padding: .65rem .85rem;
    border-left: 3px solid var(--yf-border);
    background: var(--bs-body-bg);
    color: var(--yf-muted);
    font-size: .95rem;
}

.tut-note code[b-st14bttmvb] {
    padding: .05rem .3rem;
    border-radius: 4px;
    background: var(--bs-body-bg);
    color: var(--bs-body-color);
}

/* The installer screenshot. Capped rather than full width: it is a picture of two small input
   boxes, and stretched to the column it reads as a banner instead of a detail to recognise. */
.tut-figure[b-st14bttmvb] {
    margin: 0 0 1rem;
}

.tut-figure img[b-st14bttmvb] {
    display: block;
    max-width: 100%;
    width: 420px;
    border: 1px solid var(--yf-border);
    border-radius: 8px;
    background: var(--bs-body-bg);
}

.tut-figure figcaption[b-st14bttmvb] {
    margin-top: .4rem;
    color: var(--yf-muted);
    font-size: .9rem;
}

/* The one thing on this page that is an offer rather than an instruction, so it is the one
   thing carrying the orange. */
.tut-callout[b-st14bttmvb] {
    margin: 1.25rem 0 0;
    padding: .9rem 1.1rem;
    border: 1px solid var(--brand-orange);
    border-left-width: 4px;
    border-radius: 0 8px 8px 0;
    background: var(--bs-body-bg);
}

.tut-callout h3[b-st14bttmvb] {
    margin: 0 0 .35rem;
    font-size: 1.05rem;
    font-weight: 700;
    color: var(--brand-orange);
}

.tut-callout p[b-st14bttmvb] {
    margin: 0;
    color: var(--yf-muted);
}

/* "There is no shell". The one block on the page making a guarantee rather than describing a
   feature, so it is set apart in brand blue -- the callout's orange is the sales offer, this
   is the opposite register. */
.tut-guard[b-st14bttmvb] {
    margin: 1.25rem 0 0;
    padding: 1rem 1.2rem .9rem;
    border: 1px solid var(--yf-border);
    border-left: 4px solid var(--brand-blue);
    border-radius: 0 8px 8px 0;
    background: var(--bs-body-bg);
}

.tut-guard h3[b-st14bttmvb] {
    margin: 0 0 .5rem;
    font-size: 1.05rem;
    font-weight: 700;
    color: var(--brand-blue-fg);
}

.tut-guard p[b-st14bttmvb] {
    color: var(--yf-muted);
}

.tut-guard-close[b-st14bttmvb] {
    margin: 0;
    padding-top: .6rem;
    border-top: 1px solid var(--yf-border);
    font-weight: 600;
    color: var(--brand-blue-fg);
}

/* The transcript screenshot, shown small. It is a whole page of interface, so at any size that
   fits here the words in it are unreadable -- which is why it opens full size on a click
   (wwwroot/js/lightbox.js) and why the caption says so. Small enough to read as an
   illustration, large enough that the shape of the conversation is visible. */
.tut-figure-shot img[b-st14bttmvb] {
    width: 340px;
}
/* /Components/Pages/Unsubscribe.razor.rz.scp.css */
/* Scoped to Unsubscribe.razor, a copy of Get.razor.css. */

.gt[b-6j7v4m82gj] {
    max-width: 36rem;
    margin: 0 auto;
    padding: 3.5rem 1.5rem 3rem;
    text-align: center;
}

.gt h1[b-6j7v4m82gj] {
    margin: 0 0 .75rem;
    font-size: clamp(1.9rem, 4vw, 2.6rem);
    font-weight: 700;
    color: var(--brand-blue-fg);
}

.gt-lede[b-6j7v4m82gj] {
    margin: 0 0 2rem;
    font-size: 1.1rem;
    line-height: 1.6;
}

.gt-code-label[b-6j7v4m82gj] {
    margin: 0;
    font-size: .9rem;
    color: var(--yf-muted);
}

.gt-code[b-6j7v4m82gj] {
    margin: .25rem 0 2rem;
    font-family: Consolas, "Courier New", monospace;
    font-size: 2rem;
    font-weight: 700;
    letter-spacing: .12em;
    color: var(--brand-blue-fg);
}

.gt-btn[b-6j7v4m82gj] {
    font-size: 1.2rem;
    padding: .9rem 2.2rem;
}

.gt-steps[b-6j7v4m82gj] {
    margin: 2.5rem auto 1.5rem;
    padding-left: 1.4rem;
    text-align: left;
    line-height: 1.7;
}

.gt-small[b-6j7v4m82gj] {
    font-size: .85rem;
    color: var(--yf-muted);
}
/* /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-igt40cmd4y] {
  margin: 1rem 0;
}

.entry[b-igt40cmd4y] { padding: .5rem 0; border-bottom: 1px solid var(--yf-border); }
/* 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-igt40cmd4y] { margin: .25rem 0; white-space: pre-wrap; }
.who[b-igt40cmd4y] { font-size: .75rem; text-transform: uppercase; letter-spacing: .04em; color: var(--yf-muted); }
.entry pre[b-igt40cmd4y] { background: var(--bs-body-bg); 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-igt40cmd4y] {
  /* 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: var(--bs-body-bg);
  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-igt40cmd4y] {
  border-bottom: none;
  padding-bottom: 0;
}

.entry-cont[b-igt40cmd4y] {
  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-igt40cmd4y] {
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
}

.entry-alt.entry-cont[b-igt40cmd4y] {
  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-igt40cmd4y] {
  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-igt40cmd4y] {
  color: var(--brand-blue-fg);
}

/* 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-igt40cmd4y] {
  /* 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: var(--bs-body-bg);
  border-left: 3px solid var(--yf-border);
  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: var(--yf-muted);
}

/* 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-igt40cmd4y] {
  display: block;
  font-size: .7rem;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--yf-muted);
  margin: 0 0 .2rem;
}

.entry-time[b-igt40cmd4y] { display: block; text-align: left; margin-top: .25rem; font-size: .65rem; color: var(--bs-body-color); font-variant-numeric: tabular-nums; }

/* --- shared with Diagnose.razor.css; keep the copies identical ------------- */
.muted[b-igt40cmd4y] { color: var(--yf-muted); font-size: .875rem; }
.error[b-igt40cmd4y] { color: var(--yf-danger-fg); }
.why[b-igt40cmd4y] { margin: .5rem 0; }
dl[b-igt40cmd4y] { 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-igt40cmd4y] {
  background: var(--bs-body-bg);
  border-radius: .2rem;
  padding: .05rem .35rem;
  font-size: .85em;
  font-weight: 600;
}

/* Pictures and files on a technician's message (owner, 2026-10-06). A picture opens full size
   on click (js/lightbox.js); anything else is a link. */
.attachments[b-igt40cmd4y] {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
  margin-top: .4rem;
}

.attachment-thumb[b-igt40cmd4y] {
  max-width: 12rem;
  max-height: 9rem;
  border: 1px solid var(--yf-border);
  border-radius: .3rem;
  cursor: zoom-in;
  object-fit: cover;
}

.attachment-file[b-igt40cmd4y] {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  padding: .3rem .6rem .3rem .3rem;
  border: 1px solid var(--yf-border);
  border-radius: .3rem;
  font-size: .85rem;
  text-decoration: none;
}

.attachment-badge[b-igt40cmd4y] {
  padding: .1rem .3rem;
  border-radius: .2rem;
  background: var(--yf-border);
  color: var(--bs-body-color);
  font-size: .65rem;
  font-weight: 700;
}
