/* /Components/Layout/MainLayout.razor.rz.scp.css */
.page[b-gruz37wlpu] {
    position: relative;
    display: flex;
    flex-direction: column;
}

main[b-gruz37wlpu] {
    flex: 1;
}

.sidebar[b-gruz37wlpu] {
    background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%);
}

.top-row[b-gruz37wlpu] {
    background-color: #f7f7f7;
    border-bottom: 1px solid #d6d5d5;
    justify-content: flex-end;
    height: 3.5rem;
    display: flex;
    align-items: center;
}

    .top-row[b-gruz37wlpu]  a, .top-row[b-gruz37wlpu]  .btn-link {
        white-space: nowrap;
        margin-left: 1.5rem;
        text-decoration: none;
    }

    .top-row[b-gruz37wlpu]  a:hover, .top-row[b-gruz37wlpu]  .btn-link:hover {
        text-decoration: underline;
    }

    .top-row[b-gruz37wlpu]  a:first-child {
        overflow: hidden;
        text-overflow: ellipsis;
    }

@media (max-width: 640.98px) {
    .top-row[b-gruz37wlpu] {
        justify-content: space-between;
    }

    .top-row[b-gruz37wlpu]  a, .top-row[b-gruz37wlpu]  .btn-link {
        margin-left: 0;
    }
}

@media (min-width: 641px) {
    .page[b-gruz37wlpu] {
        flex-direction: row;
    }

    .sidebar[b-gruz37wlpu] {
        width: 250px;
        height: 100vh;
        position: sticky;
        top: 0;
    }

    .top-row[b-gruz37wlpu] {
        position: sticky;
        top: 0;
        z-index: 1;
    }

    .top-row.auth[b-gruz37wlpu]  a:first-child {
        flex: 1;
        text-align: right;
        width: 0;
    }

    .top-row[b-gruz37wlpu], article[b-gruz37wlpu] {
        padding-left: 2rem !important;
        padding-right: 1.5rem !important;
    }
}

#blazor-error-ui[b-gruz37wlpu] {
    color-scheme: light only;
    background: lightyellow;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    box-sizing: border-box;
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}

    #blazor-error-ui .dismiss[b-gruz37wlpu] {
        cursor: pointer;
        position: absolute;
        right: 0.75rem;
        top: 0.5rem;
    }
/* /Components/Pages/AiReports/AiReports.razor.rz.scp.css */
/* AB#2037 — AI Reports (Preview). Scoped to this page; every colour is a theme token so both themes read. */

.air[b-hp0mz3bhz0] { display: flex; flex-direction: column; gap: 1rem; max-width: 1400px; min-width: 0; }

.air-head[b-hp0mz3bhz0] { display: flex; flex-direction: column; gap: .35rem; }
.air-head-row[b-hp0mz3bhz0] { display: flex; align-items: center; gap: .65rem; flex-wrap: wrap; }
.air-h1[b-hp0mz3bhz0] { margin: 0; font-size: 1.5rem; font-weight: 700; color: var(--ft-text); }
.air-badge[b-hp0mz3bhz0] {
    display: inline-flex; align-items: center; padding: .15rem .6rem; border-radius: 999px;
    font-size: .72rem; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
    background: var(--ft-purple-bg); color: var(--ft-purple-text); border: 1px solid var(--ft-purple);
}
.air-sub[b-hp0mz3bhz0] { margin: 0; color: var(--ft-text-muted); max-width: 70ch; }
.air-note[b-hp0mz3bhz0] { margin: 0; color: var(--ft-text-faint); font-size: .85rem; max-width: 70ch; }

.air-ask[b-hp0mz3bhz0] { display: flex; flex-direction: column; gap: .5rem; padding: 1rem 1.1rem; }
.air-label[b-hp0mz3bhz0] { font-size: .8rem; font-weight: 600; color: var(--ft-text-muted); }
.air-ask-row[b-hp0mz3bhz0] { display: flex; gap: .5rem; flex-wrap: wrap; align-items: center; }
.air-input[b-hp0mz3bhz0] { flex: 1 1 22rem; min-width: 0; }

.air-crumbs[b-hp0mz3bhz0] { display: flex; gap: .4rem; flex-wrap: wrap; align-items: center; font-size: .8rem; }
.air-crumbs-label[b-hp0mz3bhz0] { color: var(--ft-text-muted); }
.air-crumb[b-hp0mz3bhz0] {
    padding: .15rem .55rem; border-radius: 999px; background: var(--ft-surface-2);
    border: 1px solid var(--ft-border); color: var(--ft-text);
}
.air-crumb-k[b-hp0mz3bhz0] { color: var(--ft-text-muted); }

.air-asked[b-hp0mz3bhz0] { margin: 0; color: var(--ft-text-muted); font-size: .9rem; }

.air-empty[b-hp0mz3bhz0] { padding: 1rem 1.1rem; }
.air-empty p[b-hp0mz3bhz0] { margin: 0 0 .65rem; color: var(--ft-text); }

.air-chips[b-hp0mz3bhz0] { display: flex; gap: .5rem; flex-wrap: wrap; }
.air-chip[b-hp0mz3bhz0] {
    border: 1px solid var(--ft-border-strong); background: var(--ft-surface-2); color: var(--ft-text);
    border-radius: 999px; padding: .35rem .8rem; font-size: .85rem; cursor: pointer; text-align: left;
    max-width: 100%; white-space: normal;
}
.air-chip:hover:not(:disabled)[b-hp0mz3bhz0] { border-color: var(--ft-accent); color: var(--ft-accent); }
.air-chip:disabled[b-hp0mz3bhz0] { opacity: .55; cursor: default; }

.air-state[b-hp0mz3bhz0] { display: flex; gap: .65rem; align-items: center; padding: .9rem 1.1rem; color: var(--ft-text); }
.air-working[b-hp0mz3bhz0] { color: var(--ft-text-muted); }
.air-info[b-hp0mz3bhz0] { border-left: 4px solid var(--ft-blue); }
.air-warn[b-hp0mz3bhz0] { border-left: 4px solid var(--ft-amber); }
.air-err[b-hp0mz3bhz0] { border-left: 4px solid var(--ft-red); }

.air-answer[b-hp0mz3bhz0] { display: flex; flex-direction: column; gap: 1rem; }
.air-summary[b-hp0mz3bhz0] { margin: 0; font-size: 1.02rem; color: var(--ft-text); max-width: 90ch; }

.air-partial[b-hp0mz3bhz0] {
    padding: .7rem 1rem; border-radius: var(--ft-radius); background: var(--ft-amber-bg);
    border: 1px solid var(--ft-amber); color: var(--ft-text); font-size: .88rem;
}
.air-partial ul[b-hp0mz3bhz0] { margin: .35rem 0 0; padding-left: 1.2rem; }

.air-board[b-hp0mz3bhz0] {
    display: grid; gap: .75rem;
    grid-template-columns: repeat(auto-fit, minmax(min(18rem, 100%), 1fr));
}
.air-block[b-hp0mz3bhz0] { padding: .75rem .9rem; min-width: 0; }
.air-on-step[b-hp0mz3bhz0] { outline: 2px solid var(--ft-accent); outline-offset: 2px; }
.air-wide[b-hp0mz3bhz0] { grid-column: 1 / -1; }
.air-h2[b-hp0mz3bhz0] { margin: 0 0 .6rem; font-size: 1rem; font-weight: 650; color: var(--ft-text); }

.air-kpis[b-hp0mz3bhz0] {
    display: grid; gap: .6rem;
    grid-template-columns: repeat(auto-fit, minmax(min(9rem, 100%), 1fr));
}
.air-kpi[b-hp0mz3bhz0] {
    min-width: 0; padding: .5rem .65rem; border-radius: var(--ft-radius-sm);
    background: var(--ft-surface-2); border: 1px solid var(--ft-border-soft);
}
.air-kpi-v[b-hp0mz3bhz0] { font-size: 1.35rem; font-weight: 700; color: var(--ft-text); font-variant-numeric: tabular-nums; }
/* Batch 9b: "Not stated" is words, not a figure — quieter, so it never reads as a number. */
.air-kpi-v.air-kpi-none[b-hp0mz3bhz0] { font-size: 1rem; font-weight: 600; color: var(--ft-text-muted); }
.air-kpi-l[b-hp0mz3bhz0] { font-size: .8rem; color: var(--ft-text-muted); overflow-wrap: anywhere; }

.air-chart[b-hp0mz3bhz0] { width: 100%; height: 240px; cursor: pointer; }
/* AB#2225. A primary funnel is the lead of that answer, not one more equal card. 300px is the measured height. */
.air-lead .air-chart[b-hp0mz3bhz0] { height: 300px; }
.air-map[b-hp0mz3bhz0] { width: 100%; height: 320px; border-radius: var(--ft-radius-sm); overflow: hidden; }

.air-numbers[b-hp0mz3bhz0] { margin-top: .5rem; font-size: .85rem; }
.air-numbers summary[b-hp0mz3bhz0] { cursor: pointer; color: var(--ft-text-muted); }

.air-scroll[b-hp0mz3bhz0] { overflow-x: auto; max-width: 100%; }
.air-table[b-hp0mz3bhz0] { width: 100%; border-collapse: collapse; font-size: .86rem; }
.air-table th[b-hp0mz3bhz0], .air-table td[b-hp0mz3bhz0] {
    padding: .4rem .55rem; border-bottom: 1px solid var(--ft-border-soft); text-align: left; color: var(--ft-text);
    vertical-align: top;
}
.air-table thead th[b-hp0mz3bhz0] { color: var(--ft-text-muted); font-weight: 600; white-space: nowrap; }
.air-table td[b-hp0mz3bhz0] { font-variant-numeric: tabular-nums; }

.air-narrative p[b-hp0mz3bhz0] { margin: 0; color: var(--ft-text); max-width: 90ch; line-height: 1.55; }
.air-muted[b-hp0mz3bhz0] { margin: 0 0 .5rem; color: var(--ft-text-muted); }

.air-suggested[b-hp0mz3bhz0] { display: flex; flex-direction: column; gap: .45rem; }
.air-suggested-label[b-hp0mz3bhz0] { font-size: .8rem; font-weight: 600; color: var(--ft-text-muted); }

.air-source[b-hp0mz3bhz0] { position: relative; display: flex; justify-content: flex-end; margin: 0 0 .35rem; }
.air-source-btn[b-hp0mz3bhz0] {
    border: 0; background: transparent; color: var(--ft-text-muted); font: inherit;
    font-size: .75rem; cursor: pointer; padding: 0; text-decoration: underline; text-underline-offset: .15em;
}
.air-source-btn:hover[b-hp0mz3bhz0], .air-source-btn:focus-visible[b-hp0mz3bhz0] { color: var(--ft-accent); outline: 2px solid var(--ft-accent); outline-offset: 2px; }
.air-source-tip[b-hp0mz3bhz0] {
    position: absolute; right: 0; top: calc(100% + .3rem); z-index: 3; width: max-content; max-width: min(20rem, 70vw);
    margin: 0; padding: .45rem .65rem; background: var(--ft-surface); color: var(--ft-text);
    border: 1px solid var(--ft-border); border-radius: var(--ft-radius-sm); font-size: .8rem; line-height: 1.35;
}
.air-source:not(:hover):not(:focus-within):not(.air-source-open) .air-source-tip[b-hp0mz3bhz0] {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden;
    clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}
.air-replay[b-hp0mz3bhz0] { margin: 0 0 .15rem; }
.air-replay-start[b-hp0mz3bhz0], .air-replay-nav button[b-hp0mz3bhz0] {
    border: 1px solid var(--ft-border); background: var(--ft-surface-2); color: var(--ft-text);
    border-radius: 999px; padding: .3rem .75rem; font: inherit; font-size: .8rem; cursor: pointer;
}
.air-replay-start:hover[b-hp0mz3bhz0], .air-replay-nav button:hover:not(:disabled)[b-hp0mz3bhz0],
.air-replay-start:focus-visible[b-hp0mz3bhz0], .air-replay-nav button:focus-visible[b-hp0mz3bhz0] {
    border-color: var(--ft-accent); color: var(--ft-accent); outline: 2px solid var(--ft-accent); outline-offset: 2px;
}
.air-replay-nav button:disabled[b-hp0mz3bhz0] { opacity: .45; cursor: default; }
.air-replay-step[b-hp0mz3bhz0] {
    padding: .6rem .8rem; border-radius: var(--ft-radius); background: var(--ft-surface-2);
    border: 1px solid var(--ft-border); color: var(--ft-text);
}
.air-replay-count[b-hp0mz3bhz0] { margin: 0; font-size: .75rem; color: var(--ft-text-muted); }
.air-replay-text[b-hp0mz3bhz0] { margin: .25rem 0 .5rem; }
.air-replay-nav[b-hp0mz3bhz0] { display: flex; gap: .4rem; flex-wrap: wrap; }
@media (max-width: 720px) {
    .air-board[b-hp0mz3bhz0] { grid-template-columns: 1fr; }
    .air-kpis[b-hp0mz3bhz0] { grid-template-columns: 1fr 1fr; }
}
/* /Components/Pages/Claims/ClaimsWindowLine.razor.rz.scp.css */
/* AB#1371 — the claims hub's window line. Scoped: app.css is lane 0's. */

.cw-line[b-uzsdxfc5kp] {
    margin-top: 1rem;
    font-size: .78rem;
    color: var(--ft-gray-500);
    display: flex;
    align-items: center;
    gap: .6rem;
    flex-wrap: wrap;
}
/* /Components/Pages/Estimates/BidFormLayoutConfirm.razor.rz.scp.css */
/* ═══════════════════════════════════════════════════════════════════════════════════════════════
   Confirming how a bid form's columns were read (AB#1741).

   Its own file, like every estimating surface since AB#1732: app.css is the one file three lanes would
   all have to edit to do UI at once, and a merge there breaks pages nobody touched. Nothing here needs
   app.css — if it ever does, that is a join and it goes to lane 0 rather than into the shared sheet.

   Colours are tokens, never literals. A hard-coded hex looks right in the screenshot and wrong at night.
   ═══════════════════════════════════════════════════════════════════════════════════════════════ */

.wrap[b-3ajln6g463] {
    max-width: 100%;
    padding: 0 .25rem;
}

.crumb[b-3ajln6g463] {
    font-size: .85rem;
    color: var(--ft-text-muted);
    text-decoration: none;
}

.crumb:hover[b-3ajln6g463] { color: var(--ft-text); }

.muted[b-3ajln6g463] { color: var(--ft-text-muted); }

/* ── what kind of claim this is ────────────────────────────────────────────────────────────────
   "We worked this out from your headings" and "we did what you told us last time" are different
   claims about the same numbers, and only one of them is worth checking again. Two chips, two
   colours, because a reader who skims this line is deciding whether to read the grid at all. */
.provenance[b-3ajln6g463] {
    display: flex;
    align-items: center;
    gap: .6rem;
    flex-wrap: wrap;
    margin: 0 0 .8rem;
    font-size: .85rem;
}

.chip[b-3ajln6g463] {
    display: inline-block;
    padding: .2rem .55rem;
    border-radius: 999px;
    font-size: .8rem;
    font-weight: 600;
    line-height: 1.35;
    border: 1px solid transparent;
}

.chip-recalled[b-3ajln6g463] {
    background: color-mix(in srgb, var(--ft-primary) 12%, transparent);
    border-color: color-mix(in srgb, var(--ft-primary) 35%, transparent);
    color: var(--ft-primary);
}

.chip-detected[b-3ajln6g463] {
    background: var(--ft-surface-2);
    border-color: var(--ft-border);
    color: var(--ft-text-muted);
}

.header-row[b-3ajln6g463] {
    color: var(--ft-text-faint);
    font-variant-numeric: tabular-nums;
}

.notes[b-3ajln6g463] {
    margin: 0 0 .9rem;
    padding-left: 1.1rem;
    color: var(--ft-text-muted);
    font-size: .85rem;
    line-height: 1.5;
}

/* ── the grid ──────────────────────────────────────────────────────────────────────────────────
   Scrolls inside its own box and never pushes the page sideways. A bid form is 6 to 12 columns and
   the pickers give each one a floor width, so this WILL overflow on a phone — announced by a
   scrollbar on the card rather than by a clipped right edge that reads as the end of the sheet. */
.grid-wrap[b-3ajln6g463] {
    overflow-x: auto;
    margin-bottom: 1rem;
    border: 1px solid var(--ft-border-soft);
    border-radius: 8px;
}

.grid[b-3ajln6g463] {
    border-collapse: collapse;
    width: 100%;
    font-size: .82rem;
    font-variant-numeric: tabular-nums;
}

.grid th[b-3ajln6g463],
.grid td[b-3ajln6g463] {
    padding: .3rem .5rem;
    border-right: 1px solid var(--ft-border-soft);
    vertical-align: top;
    text-align: left;
    white-space: pre-wrap;
    word-break: break-word;
}

.grid thead th[b-3ajln6g463] {
    position: sticky;
    top: 0;
    background: var(--ft-surface-2);
    z-index: 1;
}

.grid .heading[b-3ajln6g463] {
    font-weight: 650;
    color: var(--ft-navy);
    min-width: 8rem;
}

.grid .picker[b-3ajln6g463] { padding: .35rem .4rem; }

.grid .picker select[b-3ajln6g463] {
    width: 100%;
    min-width: 8rem;
    font-size: .8rem;
    padding: .25rem .4rem;
}

/* The row number is the estimator's own coordinate — "row 65 of your sheet" — so it is fixed-width,
   muted and never wraps. */
.grid .rownum[b-3ajln6g463] {
    color: var(--ft-text-faint);
    white-space: nowrap;
    width: 3rem;
    background: var(--ft-surface-2);
}

/* The header block, marked out from the sample rows under it. These are the rows the fingerprint is
   taken over: a reader deciding whether a remembered layout will match the NEXT form is looking at
   exactly this band, and it must not read as more data. */
.grid .header-row-line td[b-3ajln6g463] {
    background: color-mix(in srgb, var(--ft-primary) 6%, transparent);
    font-weight: 600;
    color: var(--ft-navy);
}

.grid tbody tr:not(:last-child) td[b-3ajln6g463] { border-bottom: 1px solid var(--ft-border-soft); }

.name[b-3ajln6g463] { margin: 0 0 1rem; }

.alert[b-3ajln6g463] {
    padding: .85rem 1rem;
    margin-bottom: 1rem;
    border-left: 3px solid var(--ft-red, #b91c1c);
    border-radius: 6px;
    background: var(--ft-surface-2);
    color: var(--ft-navy);
    font-size: .88rem;
}

.ok[b-3ajln6g463] {
    margin-bottom: 1rem;
    font-size: .88rem;
    color: var(--ft-green-text, #166534);
}

.actions[b-3ajln6g463] {
    display: flex;
    gap: .5rem;
    flex-wrap: wrap;
    align-items: center;
}

/* Sticky headers cost more than they give on a short screen, where the grid is most of the viewport
   and two sticky rows leave three of data. */
@media (max-width: 700px) {
    .grid thead th[b-3ajln6g463] { position: static; }
    .grid .heading[b-3ajln6g463],
    .grid .picker select[b-3ajln6g463] { min-width: 7rem; }
}
/* /Components/Pages/Estimates/EstimateApprove.razor.rz.scp.css */
/* AB#1877 — the approve screen. Scoped: nothing here reaches another page, and app.css is lane 0's.
   Layout and colour only; every claim a test reads is markup. */

.ap[b-bzl053wudc] { max-width: 1100px; }
.ap-pad[b-bzl053wudc] { padding: 1rem 1.25rem; }
.ap-muted[b-bzl053wudc] { color: var(--ft-text-muted); line-height: 1.5; }

.ap-head[b-bzl053wudc] { margin-bottom: 1rem; }
.ap-crumbs[b-bzl053wudc] {
    display: flex; align-items: center; gap: .4rem; flex-wrap: wrap;
    font-size: .8rem; color: var(--ft-text-faint); margin-bottom: .35rem;
}
.ap-crumbs a[b-bzl053wudc] { color: var(--ft-text-faint); text-decoration: none; }
.ap-crumbs a:hover[b-bzl053wudc] { color: var(--ft-primary); }
.ap-h1[b-bzl053wudc] { margin: .2rem 0 .3rem; font-size: 1.35rem; font-weight: 650; color: var(--ft-navy); }
.ap-number[b-bzl053wudc] { font-variant-numeric: tabular-nums; }
.ap-dash[b-bzl053wudc] { margin: 0 .4rem; color: var(--ft-text-faint); }
.ap-meta[b-bzl053wudc] { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem .9rem; font-size: .88rem; color: var(--ft-text-muted); }
.ap-rev[b-bzl053wudc] { font-weight: 600; color: var(--ft-navy); font-variant-numeric: tabular-nums; }
.ap-link[b-bzl053wudc] { margin-left: auto; }

.ap-steps[b-bzl053wudc] {
    list-style: none; margin: 0 0 1rem; padding: 0;
    display: flex; flex-wrap: wrap; gap: .5rem;
}
.ap-step[b-bzl053wudc] {
    display: flex; flex-direction: column; gap: .15rem;
    padding: .5rem .75rem; border-radius: 8px; min-width: 10rem;
    border: 1px solid var(--ft-border); background: var(--ft-surface);
}
.ap-step.is-approved[b-bzl053wudc] { border-color: var(--ft-success-border, var(--ft-border)); background: var(--ft-success-bg, var(--ft-surface-2)); }
.ap-step.is-pending[b-bzl053wudc] { border-color: var(--ft-amber-border, var(--ft-border)); background: var(--ft-amber-bg); }
.ap-step-label[b-bzl053wudc] { font-weight: 600; font-size: .9rem; }
.ap-step-who[b-bzl053wudc] { font-size: .8rem; color: var(--ft-text-muted); }

.ap-kpis[b-bzl053wudc] { display: flex; flex-wrap: wrap; gap: .75rem; margin-bottom: 1rem; }
.ap-kpi[b-bzl053wudc] {
    display: flex; flex-direction: column; gap: .15rem; min-width: 12rem;
    padding: .6rem .85rem; border-radius: 8px; border: 1px solid var(--ft-border); background: var(--ft-surface);
}
.ap-kpi-label[b-bzl053wudc] { font-size: .78rem; color: var(--ft-text-muted); }
.ap-kpi-value[b-bzl053wudc] { font-size: 1.2rem; font-weight: 650; font-variant-numeric: tabular-nums; }
.ap-kpi-value.is-up[b-bzl053wudc] { color: var(--ft-amber-text); }
.ap-kpi-value.is-down[b-bzl053wudc] { color: var(--ft-text); }
.ap-kpi-note[b-bzl053wudc] { font-size: .78rem; color: var(--ft-text-muted); }
.ap-none[b-bzl053wudc] { color: var(--ft-text-faint); }

.ap-card[b-bzl053wudc] { padding: .9rem 1rem; margin-bottom: 1rem; }
.ap-h2[b-bzl053wudc] { margin: 0 0 .6rem; font-size: 1rem; font-weight: 600; }
.ap-table[b-bzl053wudc] { width: 100%; }
.ap-num[b-bzl053wudc] { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.ap-by[b-bzl053wudc] { color: var(--ft-text-muted); font-size: .85rem; }
.ap-list[b-bzl053wudc] { margin: 0; padding-left: 1.1rem; line-height: 1.6; }
.ap-sublist[b-bzl053wudc] { margin: .25rem 0 0; padding-left: 1.1rem; font-size: .88rem; color: var(--ft-text-muted); }

.ap-act[b-bzl053wudc] { border-left: 3px solid var(--ft-primary); }
.ap-note-label[b-bzl053wudc] { display: block; font-size: .85rem; margin-bottom: .3rem; color: var(--ft-text-muted); }
.ap-note[b-bzl053wudc] { width: 100%; resize: vertical; }
.ap-buttons[b-bzl053wudc] { display: flex; flex-wrap: wrap; gap: .5rem; margin-top: .6rem; }

.ap-outcome[b-bzl053wudc] {
    padding: .6rem .85rem; border-radius: 8px; margin-bottom: 1rem;
    background: var(--ft-surface-2); color: var(--ft-text); font-size: .9rem;
}
.ap-outcome.is-problem[b-bzl053wudc] { background: var(--ft-amber-bg); color: var(--ft-amber-text); }

.ap-trail[b-bzl053wudc] { list-style: none; margin: 0; padding: 0; }
.ap-trail > li[b-bzl053wudc] { padding: .45rem 0; border-bottom: 1px solid var(--ft-border); }
.ap-trail > li:last-child[b-bzl053wudc] { border-bottom: none; }
.ap-trail-what[b-bzl053wudc] { font-weight: 500; }
.ap-trail-when[b-bzl053wudc] { margin-left: .6rem; font-size: .8rem; color: var(--ft-text-muted); }
.ap-trail-note[b-bzl053wudc] {
    margin: .3rem 0 0; padding: .35rem .6rem; border-left: 3px solid var(--ft-border);
    color: var(--ft-text); font-size: .88rem; white-space: pre-wrap;
}

@media (max-width: 640px) {
    .ap-link[b-bzl053wudc] { margin-left: 0; }
    .ap-kpi[b-bzl053wudc] { min-width: 0; flex: 1 1 100%; }
}
/* /Components/Pages/Estimates/EstimateBidFormChooser.razor.rz.scp.css */
/* AB#2185 — choosing a bid's bid form from its filed documents. Scoped: nothing here reaches another page. */
.bfc[b-fog3qstjsm] {
    margin: .75rem 0 0;
    text-align: left;
}

.bfc-title[b-fog3qstjsm] {
    margin: 0 0 .35rem;
    font-size: .95rem;
    font-weight: 700;
    color: var(--ft-navy);
}

.bfc-lede[b-fog3qstjsm], .bfc-none[b-fog3qstjsm] {
    margin: 0 0 .65rem;
    font-size: .85rem;
    line-height: 1.5;
    color: var(--ft-text-muted);
}

.bfc-list[b-fog3qstjsm] {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: .4rem;
}

/* The name takes the width; the meta and the button keep theirs. A long path wraps rather than pushing the button. */
.bfc-row[b-fog3qstjsm] {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas: "name use" "meta use";
    column-gap: .75rem;
    align-items: center;
    padding: .5rem .65rem;
    border: 1px solid var(--ft-border);
    border-radius: 8px;
    background-color: var(--ft-surface);
}

.bfc-name[b-fog3qstjsm] {
    grid-area: name;
    min-width: 0;
    overflow-wrap: anywhere;
    font-size: .88rem;
    font-weight: 600;
    color: var(--ft-text);
}

.bfc-meta[b-fog3qstjsm] {
    grid-area: meta;
    font-size: .78rem;
    color: var(--ft-text-muted);
}

.bfc-likely[b-fog3qstjsm] {
    color: var(--ft-green-text);
    font-weight: 600;
}

.bfc-use[b-fog3qstjsm] {
    grid-area: use;
    white-space: nowrap;
}

.bfc-more[b-fog3qstjsm] {
    margin-top: .45rem;
    padding: 0;
    border: 0;
    background-color: transparent;
    color: var(--ft-primary);
    font: inherit;
    font-size: .85rem;
    cursor: pointer;
    text-decoration: underline;
}

.bfc-refused[b-fog3qstjsm] {
    grid-column: 1 / -1;
    margin: .4rem 0 0;
    font-size: .85rem;
    color: var(--ft-red-text);
}
/* /Components/Pages/Estimates/EstimateConcessionExportCard.razor.rz.scp.css */
/* AB#1777 — the concession on the engineer copy. Scoped (AB#1732): layout and colour only, tokens declared in both themes. */

.cx-card[b-jg55qg2521] {
    margin-top: 1rem;
    padding: .75rem .9rem;
    background: var(--ft-surface-2);
    border-left: 3px solid var(--ft-primary);
    border-radius: 0 6px 6px 0;
    min-width: 0;
}

.cx-title[b-jg55qg2521] { margin: 0 0 .35rem; font-size: .92rem; font-weight: 650; color: var(--ft-navy); }
.cx-sentence[b-jg55qg2521] { margin: 0 0 .4rem; font-size: .88rem; color: var(--ft-text); line-height: 1.5; overflow-wrap: anywhere; }
.cx-warn[b-jg55qg2521] { margin: 0 0 .4rem; font-size: .88rem; color: var(--ft-amber-text, #b45309); font-weight: 600; }
.cx-private[b-jg55qg2521] { margin: .4rem 0 0; font-size: .8rem; color: var(--ft-text-muted); }

.cx-scroll[b-jg55qg2521] { overflow-x: auto; }
.cx-table[b-jg55qg2521] { width: 100%; border-collapse: collapse; font-size: .82rem; margin: .25rem 0; }
.cx-table th[b-jg55qg2521] { text-align: left; font-weight: 600; color: var(--ft-text-muted); padding: .25rem .4rem; border-bottom: 1px solid var(--ft-border); }
.cx-table td[b-jg55qg2521] { padding: .25rem .4rem; border-bottom: 1px solid var(--ft-border-soft, var(--ft-border)); vertical-align: top; }
.cx-table .cx-num[b-jg55qg2521] { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.cx-table .cx-desc[b-jg55qg2521] { min-width: 12rem; overflow-wrap: anywhere; }
/* /Components/Pages/Estimates/EstimateConcessionPanel.razor.rz.scp.css */
/* AB#1777 — the concession panel. Scoped, for the reason every estimating surface has its own stylesheet (AB#1732):
   app.css is lane 0's and a merge there breaks pages nobody touched. Layout and colour only; bUnit loads none of this.
   Only tokens declared in BOTH themes are used (the --ft-danger / --ft-success lesson of batch AG). */

.ec-panel[b-r7l1py9c0x] {
    margin: .75rem 0 1rem;
    padding: .85rem 1rem;
    background: var(--ft-surface);
    border: 1px solid var(--ft-border);
    border-radius: 8px;
    min-width: 0;
}

.ec-title[b-r7l1py9c0x] { margin: 0 0 .25rem; font-size: 1rem; font-weight: 650; color: var(--ft-navy); }
.ec-subtitle[b-r7l1py9c0x] { margin: .9rem 0 .2rem; font-size: .9rem; font-weight: 650; color: var(--ft-navy); }
.ec-intro[b-r7l1py9c0x], .ec-hint[b-r7l1py9c0x], .ec-none[b-r7l1py9c0x], .ec-by[b-r7l1py9c0x], .ec-frozen[b-r7l1py9c0x] { margin: 0 0 .5rem; font-size: .85rem; color: var(--ft-text-muted); line-height: 1.5; }

.ec-current[b-r7l1py9c0x] {
    padding: .65rem .8rem;
    background: var(--ft-surface-2);
    border-left: 3px solid var(--ft-primary);
    border-radius: 0 6px 6px 0;
}

.ec-terms[b-r7l1py9c0x] { margin: 0 0 .4rem; font-weight: 600; color: var(--ft-text); }

.ec-figures[b-r7l1py9c0x] { display: flex; flex-wrap: wrap; gap: .4rem 1.5rem; margin: 0 0 .4rem; }
.ec-figures dt[b-r7l1py9c0x] { font-size: .75rem; color: var(--ft-text-muted); text-transform: uppercase; letter-spacing: .03em; }
.ec-figures dd[b-r7l1py9c0x] { margin: 0; font-size: 1rem; font-weight: 650; color: var(--ft-navy); font-variant-numeric: tabular-nums; }

.ec-reason[b-r7l1py9c0x] { margin: 0 0 .3rem; font-size: .88rem; color: var(--ft-text); overflow-wrap: anywhere; }

.ec-warning[b-r7l1py9c0x] { color: var(--ft-amber-text, #b45309); font-weight: 600; }
.ec-error[b-r7l1py9c0x] { margin: .5rem 0 0; color: var(--ft-red-text, #b91c1c); font-size: .85rem; }
.ec-ok[b-r7l1py9c0x] { margin: .5rem 0 0; color: var(--ft-green-text, #15803d); font-size: .85rem; }

.ec-table[b-r7l1py9c0x] { width: 100%; border-collapse: collapse; font-size: .86rem; margin: .25rem 0 .5rem; }
.ec-table th[b-r7l1py9c0x] { text-align: left; font-weight: 600; color: var(--ft-text-muted); padding: .3rem .4rem; border-bottom: 1px solid var(--ft-border); }
.ec-table td[b-r7l1py9c0x] { padding: .35rem .4rem; border-bottom: 1px solid var(--ft-border-soft, var(--ft-border)); vertical-align: middle; }
.ec-table .ec-num[b-r7l1py9c0x] { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.ec-applied td[b-r7l1py9c0x] { background: var(--ft-surface-2); font-weight: 600; }

.ec-kind[b-r7l1py9c0x], .ec-value[b-r7l1py9c0x] {
    padding: .25rem .35rem;
    border: 1px solid var(--ft-border);
    border-radius: 4px;
    background: var(--ft-surface-2);
    color: var(--ft-text);
    font: inherit;
}
.ec-value[b-r7l1py9c0x] { width: 7.5rem; margin-left: .35rem; }

.ec-actions[b-r7l1py9c0x] { white-space: nowrap; text-align: right; }

.ec-panel button[b-r7l1py9c0x] {
    padding: .3rem .65rem;
    border-radius: 4px;
    border: 1px solid var(--ft-border-strong, var(--ft-border));
    background: var(--ft-surface);
    color: var(--ft-text);
    font: inherit;
    font-size: .84rem;
    cursor: pointer;
}
.ec-panel button:disabled[b-r7l1py9c0x] { opacity: .5; cursor: not-allowed; }
.ec-panel .ec-primary[b-r7l1py9c0x] { background: var(--ft-primary); border-color: var(--ft-primary); color: #fff; }
.ec-panel .ec-quiet[b-r7l1py9c0x] { border-color: transparent; background: transparent; color: var(--ft-text-muted); }
.ec-panel .ec-remove[b-r7l1py9c0x] { margin-top: .35rem; }

.ec-apply[b-r7l1py9c0x] { margin-top: .6rem; padding: .65rem .8rem; background: var(--ft-surface-2); border-radius: 6px; }
.ec-label[b-r7l1py9c0x] { display: block; font-size: .84rem; font-weight: 600; margin-bottom: .25rem; color: var(--ft-text); }
.ec-reason-input[b-r7l1py9c0x] {
    width: 100%;
    box-sizing: border-box;
    padding: .4rem .5rem;
    border: 1px solid var(--ft-border);
    border-radius: 4px;
    background: var(--ft-surface);
    color: var(--ft-text);
    font: inherit;
}
.ec-buttons[b-r7l1py9c0x] { display: flex; gap: .5rem; margin-top: .45rem; }
/* /Components/Pages/Estimates/EstimateContactsHeader.razor.rz.scp.css */
/* AB#1875 — who is on this bid. Scoped: it sits in the workspace header and on the pipeline page, and app.css is
   lane 0's. Only tokens declared in BOTH themes are used (batch AG: --ft-success / --ft-danger are not). */

.ech[b-xove865tlv] {
    padding: .8rem 1rem;
    margin: .6rem 0;
}

.ech-head[b-xove865tlv] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: .5rem;
}

.ech-title[b-xove865tlv] {
    margin: 0;
    font-size: 1rem;
    font-weight: 600;
    color: var(--ft-navy);
}

.ech-actions[b-xove865tlv],
.ech-row[b-xove865tlv] {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    align-items: center;
}

.ech-row[b-xove865tlv] {
    margin-top: .6rem;
}

/* Three roles side by side where there is room; they wrap, never scroll sideways. */
.ech-roles[b-xove865tlv],
.ech-form[b-xove865tlv] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
    gap: .6rem 1rem;
    margin-top: .6rem;
}

.ech-role-label[b-xove865tlv] {
    font-size: .78rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .03em;
    color: var(--ft-text-muted);
    margin-bottom: .2rem;
}

.ech-fields[b-xove865tlv] {
    display: grid;
    grid-template-columns: max-content minmax(0, 1fr);
    gap: .15rem .6rem;
    margin: 0;
    font-size: .88rem;
}

.ech-fields dt[b-xove865tlv] {
    color: var(--ft-text-muted);
}

.ech-fields dd[b-xove865tlv] {
    margin: 0;
    min-width: 0;
    overflow-wrap: anywhere;
}

.ech-value[b-xove865tlv] {
    display: block;
    color: var(--ft-text);
}

.ech-source[b-xove865tlv],
.ech-quote[b-xove865tlv],
.ech-muted[b-xove865tlv],
.ech-empty[b-xove865tlv] {
    display: block;
    font-size: .78rem;
    color: var(--ft-text-muted);
}

.ech-quote[b-xove865tlv] {
    font-style: italic;
}

.ech-fieldset[b-xove865tlv] {
    border: 1px solid var(--ft-border);
    border-radius: 6px;
    padding: .5rem .7rem .7rem;
    margin: 0;
    display: grid;
    gap: .25rem;
    min-width: 0;
}

.ech-proposal[b-xove865tlv] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
    gap: .6rem 1rem;
    margin-top: .8rem;
    padding-top: .7rem;
    border-top: 1px dashed var(--ft-border);
}

.ech-warn[b-xove865tlv] {
    margin: .3rem 0 0;
    font-size: .8rem;
    color: var(--ft-amber-text);
}

.ech-error[b-xove865tlv] {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    align-items: center;
    margin-top: .5rem;
    padding: .45rem .6rem;
    border-radius: 6px;
    font-size: .85rem;
    color: var(--ft-red-text);
    background: var(--ft-red-bg);
}

.ech-saved[b-xove865tlv] {
    margin-top: .5rem;
    font-size: .85rem;
    color: var(--ft-green-text);
}
/* /Components/Pages/Estimates/EstimateDepthBasisCards.razor.rz.scp.css */
/* AB#1855 — the depth-basis cards. Scoped, for the reason every estimating surface has its own stylesheet (AB#1732):
   app.css is lane 0's and a merge there breaks pages nobody touched. Layout and colour only; bUnit loads none of this.

   A CHOICE is drawn in the amber the register uses for "not covered" — it blocks Submit, it is not an error. A
   DEFAULT is drawn on the neutral well: it is the org's own position, stated back to them. Only tokens declared in
   BOTH themes are used (the --ft-danger / --ft-success lesson of batch AG). */

.db-root[b-8li2tyqlnk] { margin-top: .25rem; }

.db-heading[b-8li2tyqlnk] {
    margin: 1rem 0 .45rem;
    font-size: .9rem;
    font-weight: 650;
    color: var(--ft-navy);
}

.db-card[b-8li2tyqlnk] {
    padding: .75rem .9rem;
    margin-bottom: .6rem;
    background: var(--ft-surface-2);
    border-radius: 0 6px 6px 0;
    border-left: 3px solid var(--ft-border-strong);
    min-width: 0;
}

.db-card.is-choice[b-8li2tyqlnk] { border-left-color: var(--ft-amber-text, #b45309); }

.db-finding[b-8li2tyqlnk] {
    margin: 0 0 .4rem;
    font-weight: 600;
    color: var(--ft-navy);
    font-size: .9rem;
    line-height: 1.5;
    overflow-wrap: anywhere;
}

.db-quote[b-8li2tyqlnk] {
    margin: 0 0 .5rem;
    padding: .35rem .6rem;
    border-left: 2px solid var(--ft-border-strong);
    font-size: .82rem;
    color: var(--ft-text-muted);
    line-height: 1.5;
    overflow-wrap: anywhere;
}

.db-quote-from[b-8li2tyqlnk] { display: block; font-weight: 600; margin-bottom: .1rem; }

.db-lines[b-8li2tyqlnk] {
    list-style: none;
    margin: 0 0 .35rem;
    padding: 0;
    font-size: .84rem;
}

.db-lines li[b-8li2tyqlnk] {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: .4rem;
    padding: .15rem 0;
    min-width: 0;
}

.db-item[b-8li2tyqlnk] { font-variant-numeric: tabular-nums; font-weight: 600; color: var(--ft-text-muted); white-space: nowrap; }

.db-desc[b-8li2tyqlnk] {
    flex: 1 1 12rem;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.db-amount[b-8li2tyqlnk] { font-variant-numeric: tabular-nums; white-space: nowrap; }

.db-show[b-8li2tyqlnk], .db-change[b-8li2tyqlnk] { font-size: .76rem; padding: .15rem .55rem; }

.db-money[b-8li2tyqlnk], .db-proposed[b-8li2tyqlnk] {
    margin: .2rem 0 .5rem;
    font-size: .85rem;
    color: var(--ft-text-muted);
    line-height: 1.5;
}

.db-options[b-8li2tyqlnk] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
    gap: .5rem;
    margin: .4rem 0 .5rem;
}

.db-option[b-8li2tyqlnk] {
    display: flex;
    gap: .5rem;
    align-items: flex-start;
    padding: .55rem .65rem;
    border: 1px solid var(--ft-border-strong);
    border-radius: 6px;
    background: var(--ft-surface, transparent);
    cursor: pointer;
    min-width: 0;
}

.db-option input[b-8li2tyqlnk] { margin-top: .25rem; flex: 0 0 auto; }

.db-option-body[b-8li2tyqlnk] {
    display: flex;
    flex-direction: column;
    gap: .25rem;
    font-size: .85rem;
    line-height: 1.5;
    min-width: 0;
    overflow-wrap: anywhere;
}

.db-proposal-sentence[b-8li2tyqlnk] { font-size: .82rem; line-height: 1.5; overflow-wrap: anywhere; }

.db-label[b-8li2tyqlnk] { display: block; font-weight: 600; font-size: .78rem; color: var(--ft-text-muted); }

.db-unattributed[b-8li2tyqlnk] { font-size: .8rem; color: var(--ft-text-muted); margin-top: .35rem; }
.db-unattributed ul[b-8li2tyqlnk] { margin: .15rem 0 0 1rem; padding: 0; }

.db-hint[b-8li2tyqlnk] { margin: 0 0 .25rem; font-size: .8rem; color: var(--ft-text-muted); }

.db-decided[b-8li2tyqlnk] { margin: .4rem 0 0; font-size: .85rem; line-height: 1.5; overflow-wrap: anywhere; }
.db-by[b-8li2tyqlnk] { color: var(--ft-text-muted); }

.db-recorder[b-8li2tyqlnk] { display: flex; flex-direction: column; gap: .35rem; margin-top: .5rem; max-width: 40rem; }

.db-reason[b-8li2tyqlnk] {
    width: 100%;
    font: inherit;
    font-size: .85rem;
    padding: .35rem .5rem;
    border: 1px solid var(--ft-border-strong);
    border-radius: 6px;
    background: var(--ft-surface, transparent);
    color: inherit;
    resize: vertical;
}

.db-recorder .ft-btn[b-8li2tyqlnk] { align-self: flex-start; }
/* /Components/Pages/Estimates/EstimateEvidenceSuggestion.razor.rz.scp.css */
/* AB#2478 — a cited suggestion under an unpriced line: quiet, and visibly not a rate. */
.est-evidence[b-n23m9epgoq] {
    margin-top: .35rem;
    padding: .4rem .55rem;
    border-left: 3px solid var(--ft-amber);
    background: var(--ft-amber-bg);
    color: var(--ft-amber-text);
    font-size: .8rem;
    line-height: 1.45;
    white-space: normal;
}

.est-evidence-figures[b-n23m9epgoq] {
    font-weight: 600;
}

.est-evidence-wide[b-n23m9epgoq] {
    margin-top: .2rem;
    color: var(--ft-red-text);
}
/* /Components/Pages/Estimates/EstimateExport.razor.rz.scp.css */
/* ═══════════════════════════════════════════════════════════════════════════════════════════════
   The Export / finish step (AB#1773 Frame F, AB#1761), as a LAYOUT.

   Its own file, like every estimating surface since AB#1732. Colours are tokens with the fallbacks the
   workspace's own strip and export pair use, so the same amber, green and red mean the same thing on
   both pages and the dark theme comes free.

   What stays INLINE in the markup, on purpose: the two audience pills. They carry the one claim on this
   page that must not depend on a stylesheet loading — which of these two files may leave the firm —
   and bUnit reads the markup, not this file.
   ═══════════════════════════════════════════════════════════════════════════════════════════════ */

.ex[b-kv7i31txdw] {
    max-width: none;   /* AB#1773 W4: fluid; prose blocks keep their own 52rem measure */
}

.ex-pad[b-kv7i31txdw] {
    padding: 1rem 1.25rem;
}

.ex-muted[b-kv7i31txdw] {
    color: var(--ft-text-muted);
    line-height: 1.55;
}

.ex-muted-small[b-kv7i31txdw] {
    font-size: .85rem;
    color: var(--ft-text-muted);
}

/* ── the header ──────────────────────────────────────────────────────────────────────────────── */
.ex-head[b-kv7i31txdw] {
    margin-bottom: 1rem;
}

.ex-head-top[b-kv7i31txdw] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: .5rem 1.25rem;
    margin-bottom: .35rem;
}

.ex-crumbs[b-kv7i31txdw] {
    display: flex;
    align-items: center;
    gap: .4rem;
    font-size: .8rem;
    color: var(--ft-text-faint);
    flex-wrap: wrap;
}

.ex-crumbs a[b-kv7i31txdw] {
    color: var(--ft-text-faint);
    text-decoration: none;
}

.ex-crumbs a:hover[b-kv7i31txdw] { color: var(--ft-primary); }

/* The bid on the left, Submit on the right — the one primary action this page is allowed, where the
   frame puts it and where an estimator's eye goes first. */
.ex-title-row[b-kv7i31txdw] {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: space-between;
    gap: .75rem 1.5rem;
}

.ex-title-text[b-kv7i31txdw] {
    min-width: 0;
    flex: 1 1 24rem;
}

.ex-h1[b-kv7i31txdw] {
    margin: .2rem 0 .3rem;
    font-size: 1.4rem;
    font-weight: 700;
    letter-spacing: -.02em;
    color: var(--ft-navy);
    overflow-wrap: anywhere;
}

.ex-number[b-kv7i31txdw] {
    font-variant-numeric: tabular-nums;
}

.ex-dash[b-kv7i31txdw] {
    color: var(--ft-text-muted);
    font-weight: 500;
    margin: 0 .35rem;
}

.ex-meta[b-kv7i31txdw] {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    align-items: center;
    color: var(--ft-text-muted);
    font-size: .88rem;
}

.ex-submit[b-kv7i31txdw] {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    align-items: center;
    padding-top: .35rem;
}

.ex-submit-error[b-kv7i31txdw] {
    color: var(--ft-danger, #b91c1c);
    font-size: .85rem;
}

.ex-submitted[b-kv7i31txdw] {
    color: var(--ft-success-text, #166534);
    font-size: .85rem;
    padding-top: .5rem;
}

/* ── one progress story (AB#1751), on the finish step ────────────────────────────────────────
   The same element in the same two colours as the workspace's strip. `.is-done` is the third state
   this page has and the workspace does not: a revision that is no longer a draft. */
.ex-gate[b-kv7i31txdw] {
    display: flex;
    flex-wrap: wrap;
    gap: .35rem .9rem;
    align-items: baseline;
    padding: .6rem .9rem;
    margin-bottom: 1rem;
    border-radius: 0 6px 6px 0;
    background: var(--ft-surface-2);
    font-size: .88rem;
    line-height: 1.5;
}

.ex-gate.is-blocked[b-kv7i31txdw] { border-left: 3px solid var(--ft-amber, #f59e0b); }
.ex-gate.is-ready[b-kv7i31txdw]   { border-left: 3px solid var(--ft-green-text); }
.ex-gate.is-done[b-kv7i31txdw]    { border-left: 3px solid var(--ft-border-strong); }

.ex-gate-msg[b-kv7i31txdw] {
    font-weight: 600;
    color: var(--ft-navy);
}

.ex-gate.is-blocked .ex-gate-msg[b-kv7i31txdw] { color: var(--ft-amber-text, #b45309); }
.ex-gate.is-ready   .ex-gate-msg[b-kv7i31txdw] { color: var(--ft-green-text); }

.ex-gate-jumps[b-kv7i31txdw] {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    margin-left: auto;
}

/* Links that look like the workspace's jump buttons, so the two strips read as one control. */
.ex-gate-jump[b-kv7i31txdw] {
    font-size: .85rem;
    font-weight: 600;
    color: var(--ft-primary);
    text-decoration: underline;
    text-underline-offset: 2px;
}

.ex-gate-jump[b-kv7i31txdw]::before { content: "\2192\00a0"; }

.ex-gate-jump:hover[b-kv7i31txdw] { text-decoration-thickness: 2px; }

/* ── the cards ───────────────────────────────────────────────────────────────────────────────── */
.ex-card[b-kv7i31txdw] {
    padding: 1rem 1.25rem;
    margin-bottom: 1rem;
}

.ex-card-last[b-kv7i31txdw] {
    margin-bottom: 2rem;
}

.ex-h2[b-kv7i31txdw] {
    margin: 0 0 .3rem;
    font-size: 1.05rem;
    font-weight: 650;
    color: var(--ft-navy);
}

.ex-h3[b-kv7i31txdw] {
    margin: 0 0 .4rem;
    font-size: .9rem;
    font-weight: 650;
    color: var(--ft-navy);
}

.ex-blurb[b-kv7i31txdw] {
    margin: 0 0 .9rem;
    color: var(--ft-text-muted);
    font-size: .87rem;
    line-height: 1.5;
    max-width: 52rem;
}

.ex-blurb-last[b-kv7i31txdw] { margin-bottom: 0; }

/* ── the two copies, side by side ─────────────────────────────────────────────────────────────
   Two equal columns that stack under the shell's own narrow breakpoint. The client copy carries the
   accent on its top edge and the internal copy carries the danger colour — the frame's shape, and the
   workspace's, so the pair reads the same wherever it is met. */
.ex-pair[b-kv7i31txdw] {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1rem;
    align-items: stretch;
}

@media (max-width: 700px) {
    .ex-pair[b-kv7i31txdw] {
        grid-template-columns: minmax(0, 1fr);
    }
}

.ex-copy[b-kv7i31txdw] {
    border: 1px solid var(--ft-border-strong);
    border-radius: 8px;
    padding: .85rem 1rem;
    min-width: 0;
}

.ex-copy-client[b-kv7i31txdw] {
    border-top: 3px solid var(--ft-primary);
}

.ex-copy-internal[b-kv7i31txdw] {
    border-color: var(--ft-danger-border, #fca5a5);
    border-top: 3px solid var(--ft-danger-text, #b91c1c);
    background: rgba(185, 28, 28, .04);
}

.ex-copy-title[b-kv7i31txdw] {
    margin-top: .5rem;
    font-weight: 650;
    color: var(--ft-navy);
    font-size: .98rem;
}

.ex-copy-blurb[b-kv7i31txdw] {
    margin-top: .3rem;
    font-size: .85rem;
    color: var(--ft-text-muted);
    line-height: 1.5;
    overflow-wrap: anywhere;
}

.ex-copy-cta[b-kv7i31txdw] {
    display: inline-block;
    margin-top: .8rem;
    font-size: .82rem;
    padding: .35rem .9rem;
    text-decoration: none;
}

/* ── notes under the pair: what the engineer copy will actually be ──────────────────────────── */
.ex-note[b-kv7i31txdw] {
    margin-top: 1rem;
    padding: .75rem .9rem;
    background: var(--ft-surface-2);
    border-radius: 0 6px 6px 0;
    font-size: .85rem;
    color: var(--ft-text-muted);
    line-height: 1.5;
}

.ex-note-warn[b-kv7i31txdw] { border-left: 3px solid var(--ft-amber, #f59e0b); }
.ex-note-info[b-kv7i31txdw] { border-left: 3px solid var(--ft-primary); }

.ex-note-small[b-kv7i31txdw] {
    margin-top: 0;
    margin-bottom: .35rem;
    padding: .5rem .75rem;
}

.ex-note-title[b-kv7i31txdw] {
    font-weight: 650;
    color: var(--ft-navy);
    font-size: .9rem;
}

.ex-note-body[b-kv7i31txdw] {
    margin-top: .3rem;
}

.ex-notes[b-kv7i31txdw] {
    margin-top: .9rem;
}

/* ── the rules card ──────────────────────────────────────────────────────────────────────────── */
.ex-rules-head[b-kv7i31txdw] {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 1rem;
}

.ex-rules-edit[b-kv7i31txdw] {
    font-size: .85rem;
    white-space: nowrap;
}

.ex-rules[b-kv7i31txdw] {
    display: flex;
    flex-wrap: wrap;
    gap: 1.5rem 2.5rem;
}

.ex-rule-label[b-kv7i31txdw] {
    font-size: .78rem;
    color: var(--ft-text-muted);
}

.ex-rule-value[b-kv7i31txdw] {
    font-weight: 650;
    color: var(--ft-navy);
    font-variant-numeric: tabular-nums;
}

.ex-rule-basis[b-kv7i31txdw] {
    font-size: .75rem;
    color: var(--ft-text-faint);
    max-width: 18rem;
    line-height: 1.4;
}

.ex-rules-question[b-kv7i31txdw] {
    margin: .9rem 0 0;
    padding-top: .7rem;
    border-top: 1px solid var(--ft-border-soft);
    color: var(--ft-navy);
    font-size: .9rem;
    font-weight: 600;
}

.ex-rules-apply[b-kv7i31txdw] {
    margin-top: .8rem;
    display: flex;
    flex-wrap: wrap;
    gap: .6rem;
    align-items: center;
}

.ex-rules-apply-btn[b-kv7i31txdw] {
    font-size: .82rem;
    padding: .35rem .8rem;
}

.ex-rules-notes[b-kv7i31txdw] {
    margin: .4rem 0 0;
    padding-left: 1.1rem;
    font-size: .8rem;
    color: var(--ft-text-faint);
}
/* /Components/Pages/Estimates/EstimateHistory.razor.rz.scp.css */
/* AB#1645 / AB#1638 — the "what we charged before" screen.
 *
 * SCOPED, which is what lets several lanes build UI at once: Blazor CSS isolation rewrites every selector
 * here with this component's own attribute, so nothing in this file can reach another page and nothing in
 * another page's file can reach this one. wwwroot/app.css is the shared surface and is deliberately NOT
 * touched.
 *
 * EVERY colour is a --ft-* token. The app is dark-first with a light override (html[data-theme="light"]),
 * so a literal here would produce a screen that is unreadable in one of the two themes the product ships.
 *
 * COLOURS ARE SET WITH background-color, NEVER the background shorthand. AngleSharp.Css 1.0.1 — the engine
 * bUnit brings — resolves var() in the longhand and returns empty for the same var() inside the shorthand,
 * so a shorthand rule is correct in a browser and untestable here. RevisionCompare.razor.css records the
 * same finding; it is the reason a swallowed CSS rule is invisible to every DOM test.
 */

.eh[b-wk69sgzsnh] {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

.eh-pad[b-wk69sgzsnh] { padding: 1.25rem 1.5rem; }

.eh-head[b-wk69sgzsnh] { padding: .25rem 0 0; }

.eh-crumbs[b-wk69sgzsnh] {
    display: flex;
    gap: .4rem;
    align-items: center;
    font-size: .82rem;
    color: var(--ft-text-muted);
    margin-bottom: .35rem;
    flex-wrap: wrap;
}

.eh-crumbs a[b-wk69sgzsnh] { color: var(--ft-text-muted); text-decoration: none; }
.eh-crumbs a:hover[b-wk69sgzsnh] { text-decoration: underline; }

.eh-h1[b-wk69sgzsnh] {
    margin: 0;
    font-size: 1.45rem;
    font-weight: 700;
    color: var(--ft-navy);
}

.eh-h2[b-wk69sgzsnh] {
    margin: 0;
    font-size: .95rem;
    font-weight: 650;
    color: var(--ft-navy);
}

.eh-sub[b-wk69sgzsnh] {
    margin: .3rem 0 0;
    font-size: .9rem;
    line-height: 1.5;
    color: var(--ft-text-muted);
    max-width: 52rem;
}

.eh-muted[b-wk69sgzsnh] {
    margin: .5rem 0 0;
    font-size: .84rem;
    line-height: 1.5;
    color: var(--ft-text-muted);
}

/* ── how hard we looked ───────────────────────────────────────────────────────────────────────── */

.eh-strip[b-wk69sgzsnh] { padding: 1rem 1.25rem; }

.eh-kpis[b-wk69sgzsnh] {
    display: flex;
    flex-wrap: wrap;
    gap: 2rem;
}

.eh-kpi-l[b-wk69sgzsnh] {
    font-size: .78rem;
    color: var(--ft-text-muted);
    text-transform: uppercase;
    letter-spacing: .03em;
}

.eh-kpi-v[b-wk69sgzsnh] {
    font-size: 1.5rem;
    font-weight: 700;
    color: var(--ft-navy);
    font-variant-numeric: tabular-nums;
}

.eh-jobs[b-wk69sgzsnh] {
    margin-left: .4rem;
    font-variant-numeric: tabular-nums;
    color: var(--ft-navy);
}

/* ── one bid line ─────────────────────────────────────────────────────────────────────────────── */

.eh-lines[b-wk69sgzsnh] {
    display: flex;
    flex-direction: column;
    gap: .75rem;
}

.eh-line[b-wk69sgzsnh] { padding: .9rem 1.1rem; }

.eh-line-head[b-wk69sgzsnh] {
    display: flex;
    gap: 1rem;
    align-items: baseline;
    flex-wrap: wrap;
}

.eh-line-id[b-wk69sgzsnh] {
    display: flex;
    gap: .4rem;
    align-items: center;
    min-width: 5.5rem;
}

.eh-code[b-wk69sgzsnh] {
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--ft-navy);
}

.eh-line-desc[b-wk69sgzsnh] {
    flex: 1 1 22rem;
    min-width: 0;
    font-size: .92rem;
    color: var(--ft-navy);
    line-height: 1.45;
    overflow-wrap: anywhere;
}

.eh-line-now[b-wk69sgzsnh] {
    font-variant-numeric: tabular-nums;
    font-size: .92rem;
    color: var(--ft-navy);
    white-space: nowrap;
}

/* ── the past instances ───────────────────────────────────────────────────────────────────────── */

.eh-matches[b-wk69sgzsnh] {
    list-style: none;
    margin: .7rem 0 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: .5rem;
}

.eh-match[b-wk69sgzsnh] {
    display: flex;
    gap: 1rem;
    align-items: flex-start;
    padding: .55rem .75rem;
    border-radius: 6px;
    /* The evidence rows are the ONE part of this screen that is tinted. Everything else is quiet, so the
       eye lands on the thing the page exists to show. */
    background-color: var(--ft-surface-2);
    border-left: 3px solid var(--ft-primary);
}

.eh-match-money[b-wk69sgzsnh] {
    min-width: 8rem;
    display: flex;
    flex-direction: column;
}

.eh-rate[b-wk69sgzsnh] {
    font-size: 1.05rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--ft-navy);
}

.eh-per[b-wk69sgzsnh] {
    font-size: .76rem;
    color: var(--ft-text-muted);
}

.eh-match-body[b-wk69sgzsnh] { flex: 1 1 auto; min-width: 0; }

.eh-match-desc[b-wk69sgzsnh] {
    font-size: .88rem;
    color: var(--ft-navy);
    line-height: 1.45;
    overflow-wrap: anywhere;
}

/* The citation. Deliberately not muted-to-invisible: it is the claim, not a footnote. */
.eh-cite[b-wk69sgzsnh] {
    display: flex;
    gap: .5rem;
    flex-wrap: wrap;
    margin-top: .2rem;
    font-size: .8rem;
    color: var(--ft-navy);
}

.eh-jobname[b-wk69sgzsnh] { color: var(--ft-text-muted); }

.eh-match-meta[b-wk69sgzsnh] {
    display: flex;
    gap: .35rem;
    flex-wrap: wrap;
    margin-top: .35rem;
}

/* The honest refusal, and it is NOT smaller or greyer than the matches above it. */
.eh-none[b-wk69sgzsnh] {
    margin: .7rem 0 0;
    font-size: .86rem;
    line-height: 1.5;
    color: var(--ft-text-muted);
    padding: .5rem .75rem;
    border-radius: 6px;
    background-color: var(--ft-surface-2);
    border-left: 3px solid var(--ft-border);
}

/* ── the proposals ───────────────────────────────────────────────────────────────────────────── */

.eh-propose[b-wk69sgzsnh] {
    margin-top: .9rem;
    padding-top: .8rem;
    border-top: 1px solid var(--ft-border);
}

.eh-propose-head[b-wk69sgzsnh] { margin-bottom: .5rem; }

.eh-props[b-wk69sgzsnh] {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: .5rem;
}

.eh-prop[b-wk69sgzsnh] {
    display: flex;
    gap: 1rem;
    align-items: flex-start;
    justify-content: space-between;
    flex-wrap: wrap;
    padding: .55rem .75rem;
    border-radius: 6px;
    background-color: var(--ft-surface-2);
    border-left: 3px solid var(--ft-amber, #f59e0b);
}

.eh-prop-body[b-wk69sgzsnh] { flex: 1 1 24rem; min-width: 0; }

.eh-prop-desc[b-wk69sgzsnh] {
    font-size: .9rem;
    color: var(--ft-navy);
    line-height: 1.45;
    overflow-wrap: anywhere;
}

.eh-prop-meta[b-wk69sgzsnh] {
    display: flex;
    gap: .4rem;
    flex-wrap: wrap;
    align-items: center;
    margin-top: .3rem;
}

.eh-prop-actions[b-wk69sgzsnh] {
    display: flex;
    gap: .4rem;
    align-items: center;
    flex-wrap: wrap;
}

.eh-btn[b-wk69sgzsnh] {
    font-size: .8rem;
    padding: .25rem .7rem;
}

/* ── chips ───────────────────────────────────────────────────────────────────────────────────── */

.eh-chip[b-wk69sgzsnh] {
    display: inline-block;
    padding: .1rem .45rem;
    border-radius: 999px;
    font-size: .74rem;
    line-height: 1.5;
    white-space: normal;
}

.eh-chip-quiet[b-wk69sgzsnh] {
    background-color: var(--ft-surface);
    color: var(--ft-text-muted);
}

.eh-chip-warn[b-wk69sgzsnh] {
    background-color: var(--ft-amber-bg, #fbf1dc);
    color: var(--ft-amber-text, #92600a);
}

.eh-chip-ok[b-wk69sgzsnh] {
    background-color: var(--ft-green-bg, #e6f4ec);
    color: var(--ft-green-text, #0f7a4d);
}

/* ── foot ────────────────────────────────────────────────────────────────────────────────────── */

.eh-foot[b-wk69sgzsnh] {
    display: flex;
    gap: 1rem;
    align-items: center;
    flex-wrap: wrap;
    padding-bottom: 1rem;
}

.eh-error[b-wk69sgzsnh] {
    font-size: .85rem;
    color: var(--ft-red-text, #b42318);
}
/* /Components/Pages/Estimates/EstimateKeyDates.razor.rz.scp.css */
/* AB#1629 — the key dates panel in the workspace header: three rows, each a date and where it came from. */
.kd[b-3ga11cyn0r] {
    margin: .5rem 0;
    padding: .55rem .8rem;
    border: 1px solid var(--ft-border);
    border-radius: 8px;
    background: var(--ft-surface);
    font-size: .85rem;
}

.kd-head[b-3ga11cyn0r] {
    display: flex;
    align-items: center;
    gap: .75rem;
    margin-bottom: .3rem;
}

.kd-title[b-3ga11cyn0r] { font-weight: 650; color: var(--ft-navy); }

.kd-ics[b-3ga11cyn0r] { margin-left: auto; font-size: .8rem; }

.kd-list[b-3ga11cyn0r] { margin: 0; display: grid; gap: .25rem; }

.kd-row[b-3ga11cyn0r] {
    display: grid;
    grid-template-columns: 9.5rem 1fr;
    gap: .75rem;
    align-items: baseline;
}

.kd-row dt[b-3ga11cyn0r] { font-weight: 600; color: var(--ft-text-muted); }

.kd-row dd[b-3ga11cyn0r] { margin: 0; min-width: 0; }

.kd-when[b-3ga11cyn0r] { font-weight: 650; color: var(--ft-text); margin-right: .5rem; }

.kd-cites[b-3ga11cyn0r] { display: inline; }

.kd-cite[b-3ga11cyn0r] {
    color: var(--ft-text-muted);
    font-size: .8rem;
    overflow-wrap: anywhere;
    margin-right: .5rem;
}

.kd-muted[b-3ga11cyn0r] { color: var(--ft-text-muted); font-size: .8rem; }

.kd-warn[b-3ga11cyn0r] { color: var(--ft-amber-text); font-weight: 600; }

.kd-values[b-3ga11cyn0r] { margin: .15rem 0 0; padding-left: 1.1rem; }

.kd-current[b-3ga11cyn0r] {
    display: inline-block;
    margin-right: .5rem;
    padding: 0 .4rem;
    border-radius: 999px;
    font-size: .72rem;
    background: var(--ft-green-bg, var(--ft-surface-2));
    color: var(--ft-green-text);
}

@media (max-width: 700px) {
    .kd-row[b-3ga11cyn0r] { grid-template-columns: 1fr; gap: .1rem; }
}

/* AB#2184 — hosted inside the pack review's own "Key dates" card: the card is the border and the heading. */
.kd-embedded[b-3ga11cyn0r] {
    margin: 0 0 .6rem;
    padding: 0;
    border: 0;
    background: transparent;
}
/* /Components/Pages/Estimates/EstimateLevelling.razor.rz.scp.css */
/* ═══════════════════════════════════════════════════════════════════════════════════════════════
   Bid levelling (AB#1794) — the round after submission, as a LAYOUT.

   Its own file, like every estimating surface since AB#1732: app.css is the one stylesheet three lanes
   would all have to edit to do UI at once, and a merge there breaks pages nobody touched.

   It borrows the Questions step's shapes deliberately, through the same tokens rather than the same
   selectors. This screen is that one from the other direction, and the two should not argue about what
   amber means or which side the state edge is on — but CSS isolation means sharing a class name across
   two components shares nothing, so what is shared has to be the token.

   What this file may be trusted with: layout and colour. bUnit never loads a stylesheet, so nothing here
   carries a claim a test has to see — the counts, the sentences and the links are all markup.
   ═══════════════════════════════════════════════════════════════════════════════════════════════ */

.lv[b-7ovttemnl3] {
    max-width: none;
}

.lv-pad[b-7ovttemnl3] {
    padding: 1rem 1.25rem;
}

.lv-muted[b-7ovttemnl3] {
    color: var(--ft-text-muted);
    line-height: 1.55;
}

/* ── the header ──────────────────────────────────────────────────────────────────────────────── */
.lv-head[b-7ovttemnl3] {
    margin-bottom: 1rem;
}

.lv-crumbs[b-7ovttemnl3] {
    display: flex;
    align-items: center;
    gap: .4rem;
    font-size: .8rem;
    color: var(--ft-text-faint);
    flex-wrap: wrap;
    margin-bottom: .35rem;
}

.lv-crumbs a[b-7ovttemnl3] {
    color: var(--ft-text-faint);
    text-decoration: none;
}

.lv-crumbs a:hover[b-7ovttemnl3] { color: var(--ft-primary); }

.lv-h1[b-7ovttemnl3] {
    margin: .2rem 0 .3rem;
    font-size: 1.35rem;
    font-weight: 650;
    color: var(--ft-navy);
}

.lv-number[b-7ovttemnl3] { font-variant-numeric: tabular-nums; }
.lv-dash[b-7ovttemnl3] { margin: 0 .4rem; color: var(--ft-text-faint); }

.lv-meta[b-7ovttemnl3] {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: .5rem .75rem;
    font-size: .85rem;
    color: var(--ft-text-muted);
}

.lv-rev[b-7ovttemnl3] {
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    color: var(--ft-navy);
}

/* ── the counts: how many open, how many answered, without hunting ───────────────────────────── */
.lv-strip[b-7ovttemnl3] {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: .4rem .6rem;
    padding: .6rem .9rem;
    margin-bottom: 1rem;
    border-radius: 0 6px 6px 0;
    background: var(--ft-surface-2);
    font-size: .88rem;
    font-weight: 600;
    line-height: 1.5;
    color: var(--ft-navy);
}

.lv-strip.is-open[b-7ovttemnl3] {
    border-left: 3px solid var(--ft-amber, #f59e0b);
    color: var(--ft-amber-text, #b45309);
}

.lv-strip.is-clear[b-7ovttemnl3] {
    border-left: 3px solid var(--ft-green-text);
    color: var(--ft-green-text);
}

/* The confirmation of what the last answer DID. It sits under the strip, reads as a consequence rather than
   a warning, and is gone on the next load — a revision existing is the strip's business, not this one's. */
.lv-opened[b-7ovttemnl3] {
    margin-bottom: 1rem;
    border-left: 3px solid var(--ft-primary);
}

.lv-opened p[b-7ovttemnl3] { margin: 0; font-size: .88rem; font-weight: 600; }

.lv-opened a[b-7ovttemnl3] { color: var(--ft-primary); }

/* "Nothing here is answered for you" is a standing fact about the screen, not part of the count. */
.lv-auto[b-7ovttemnl3] {
    font-weight: 400;
    color: var(--ft-text-muted);
}

/* ── a round ─────────────────────────────────────────────────────────────────────────────────── */
.lv-round[b-7ovttemnl3],
.lv-record[b-7ovttemnl3] {
    padding: 1rem 1.25rem;
    margin-bottom: 1rem;
}

.lv-h2[b-7ovttemnl3] {
    margin: 0 0 .35rem;
    font-size: 1.05rem;
    font-weight: 650;
    color: var(--ft-navy);
}

.lv-round-head[b-7ovttemnl3] {
    padding-bottom: .6rem;
    margin-bottom: .6rem;
    border-bottom: 1px solid var(--ft-border);
}

/* Term and value on one line each, so a round's attribution reads as a fact rather than as a form. */
.lv-round-meta[b-7ovttemnl3] {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: .15rem .6rem;
    margin: 0;
    font-size: .82rem;
}

.lv-round-meta dt[b-7ovttemnl3] {
    color: var(--ft-text-faint);
}

.lv-round-meta dd[b-7ovttemnl3] {
    margin: 0;
    color: var(--ft-navy);
}

/* ── one question ────────────────────────────────────────────────────────────────────────────── */
.lv-q[b-7ovttemnl3] {
    padding: .75rem 0;
    border-bottom: 1px solid var(--ft-border);
}

.lv-q:last-child[b-7ovttemnl3] { border-bottom: 0; padding-bottom: 0; }

.lv-q-top[b-7ovttemnl3] {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: .5rem;
    margin-bottom: .35rem;
}

.lv-q-against[b-7ovttemnl3] {
    font-size: .82rem;
    font-weight: 600;
    color: var(--ft-text-muted);
}

/* Their words. Held to a reading measure rather than the full width of a wide screen: this is a
   sentence somebody transcribed from a letter, and a 1200px line of it is unreadable. */
.lv-q-text[b-7ovttemnl3] {
    margin: 0 0 .4rem;
    max-width: 52rem;
    line-height: 1.55;
    color: var(--ft-navy);
}

/* Ours. Set apart with an edge, because on this screen the answer is the record. */
.lv-q-answer[b-7ovttemnl3] {
    margin: 0 0 .25rem;
    padding-left: .7rem;
    border-left: 3px solid var(--ft-primary);
    max-width: 52rem;
    line-height: 1.55;
    color: var(--ft-navy);
    font-weight: 600;
}

.lv-q-when[b-7ovttemnl3],
.lv-q-revision[b-7ovttemnl3] {
    margin: 0 0 .3rem;
    font-size: .78rem;
    color: var(--ft-text-faint);
}

.lv-q-revision a[b-7ovttemnl3] { color: var(--ft-primary); }

.lv-q-cta[b-7ovttemnl3] { margin-top: .35rem; }

/* ── the forms ───────────────────────────────────────────────────────────────────────────────── */
.lv-form[b-7ovttemnl3] {
    margin-top: .5rem;
    padding: .75rem;
    border-radius: 6px;
    background: var(--ft-surface-2);
}

.lv-label[b-7ovttemnl3] {
    display: block;
    margin: .5rem 0 .15rem;
    font-size: .82rem;
    font-weight: 600;
    color: var(--ft-navy);
}

.lv-hint[b-7ovttemnl3] {
    margin: 0 0 .3rem;
    font-size: .78rem;
    line-height: 1.45;
    color: var(--ft-text-muted);
}

.lv-check[b-7ovttemnl3] {
    display: flex;
    align-items: center;
    gap: .45rem;
    margin-top: .6rem;
    font-size: .85rem;
    color: var(--ft-navy);
}

.lv-grid[b-7ovttemnl3] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
    gap: .5rem 1rem;
}

.lv-actions[b-7ovttemnl3] {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    margin-top: .75rem;
}

.lv-failed[b-7ovttemnl3] {
    margin: .75rem 0 0;
    padding: .6rem .9rem;
    border-left: 3px solid var(--ft-danger, #dc2626);
    border-radius: 0 6px 6px 0;
    background: var(--ft-surface-2);
    font-size: .88rem;
    color: var(--ft-danger-text, #b91c1c);
}
/* /Components/Pages/Estimates/EstimateListElsewhere.razor.rz.scp.css */
/* AB#2479 — the list's "matches in All bids" note: the empty state's own measure, with its one action beside it. */
.el-elsewhere[b-afbm1vtm6v] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.75rem 1rem;
    padding: 1.5rem;
    line-height: 1.55;
}

.el-elsewhere-text[b-afbm1vtm6v] {
    color: var(--ft-text-muted);
}
/* /Components/Pages/Estimates/EstimateNegotiationMemo.razor.rz.scp.css */
/* AB#1655 — the memo card's own padding. It used the levelling page's .lv-pad, which is scoped to EstimateLevelling.razor
   and so never reached this component: in the browser the memo's text sat on the card's edge (22 Oct). */
.memo-pad[b-nsulk9bfye] {
    padding: 1rem 1.25rem;
}
/* /Components/Pages/Estimates/EstimatePipeline.razor.rz.scp.css */
/* AB#1630 — a bid's pipeline page. Scoped: nothing here reaches another page, and app.css is lane 0's. */

.pl[b-6daqa8h3rc] {
    max-width: 860px;
}

.pl-pad[b-6daqa8h3rc] {
    padding: 1.2rem;
}

.pl-crumbs[b-6daqa8h3rc] {
    display: flex;
    flex-wrap: wrap;
    gap: .4rem;
    font-size: .85rem;
    color: var(--ft-text-muted);
    margin-bottom: .4rem;
}

.pl-h1[b-6daqa8h3rc] {
    margin: .2rem 0 .3rem;
    font-size: 1.4rem;
    font-weight: 700;
    color: var(--ft-navy);
}

.pl-h2[b-6daqa8h3rc] {
    margin: 0 0 .75rem;
    font-size: 1.05rem;
    font-weight: 600;
}

.pl-muted[b-6daqa8h3rc] {
    color: var(--ft-text-muted);
    font-size: .88rem;
}

.pl-card[b-6daqa8h3rc] {
    padding: 1rem 1.1rem;
    margin-top: 1rem;
}

.pl-grid[b-6daqa8h3rc] {
    display: grid;
    grid-template-columns: minmax(10rem, 14rem) minmax(0, 1fr);
    gap: .6rem 1rem;
    align-items: center;
}

.pl-row[b-6daqa8h3rc] {
    display: flex;
    flex-wrap: wrap;
    gap: .75rem;
    align-items: center;
    margin-top: .9rem;
}

.pl-checks[b-6daqa8h3rc] {
    display: flex;
    flex-wrap: wrap;
    gap: .4rem 1rem;
}

.pl-check[b-6daqa8h3rc] {
    display: inline-flex;
    gap: .35rem;
    align-items: center;
    font-size: .9rem;
}

.pl-note[b-6daqa8h3rc],
.pl-error[b-6daqa8h3rc],
.pl-saved[b-6daqa8h3rc] {
    padding: .7rem .9rem;
    border-radius: 8px;
    font-size: .88rem;
    margin-top: .75rem;
}

.pl-note[b-6daqa8h3rc] {
    background: var(--ft-surface-2);
    color: var(--ft-text-muted);
}

.pl-error[b-6daqa8h3rc] {
    background: var(--ft-amber-bg);
    color: var(--ft-amber-text);
    display: flex;
    flex-wrap: wrap;
    gap: .6rem;
    align-items: center;
}

.pl-saved[b-6daqa8h3rc] {
    background: var(--ft-surface-2);
    color: var(--ft-text);
}

/* AB#2274 — the decision a deciding stage records, asked for beside the stage; and the marker for a deciding stage with
   no decision on it. The marker is words, not colour alone. */
.pl-decide[b-6daqa8h3rc] {
    grid-column: 1 / -1;
    border-left: 3px solid var(--ft-amber-text);
    padding: .5rem 0 .5rem .9rem;
}

.pl-decide-lead[b-6daqa8h3rc] {
    margin: 0 0 .6rem;
    font-size: .9rem;
}

.pl-flag[b-6daqa8h3rc] {
    display: inline-block;
    padding: .05rem .5rem;
    border-radius: 999px;
    background: var(--ft-amber-bg);
    color: var(--ft-amber-text);
    font-size: .8rem;
    font-weight: 600;
}

.pl-history[b-6daqa8h3rc] {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: .55rem;
}

.pl-history li[b-6daqa8h3rc] {
    display: grid;
    grid-template-columns: 11rem minmax(0, 1fr);
    gap: .1rem 1rem;
}

.pl-history .pl-muted[b-6daqa8h3rc] {
    grid-column: 2;
}

.pl-when[b-6daqa8h3rc] {
    font-variant-numeric: tabular-nums;
    color: var(--ft-text-muted);
    font-size: .85rem;
}

.pl-move[b-6daqa8h3rc] {
    font-weight: 600;
}

@media (max-width: 640px) {
    .pl-grid[b-6daqa8h3rc],
    .pl-history li[b-6daqa8h3rc] {
        grid-template-columns: minmax(0, 1fr);
    }

    .pl-history .pl-muted[b-6daqa8h3rc] {
        grid-column: 1;
    }
}
/* /Components/Pages/Estimates/EstimateProposalBand.razor.rz.scp.css */
/* AB#1854 — sits in the proposal's prose run, after the evidence, like .est-proposal-because does. */
.est-proposal-band[b-d9zc7me8y9] {
    margin-left: .3rem;
    color: var(--ft-navy);
}
/* /Components/Pages/Estimates/EstimateQuantityBasisPanel.razor.rz.scp.css */
/* AB#1871 — the two quantities. Tokens only, so the dark theme comes free. */
.est-basis[b-e5lgy1aqvv] {
    margin-top: .8rem;
    padding: .75rem .9rem;
    border: 1px solid var(--ft-border);
    border-radius: 6px;
    background: var(--ft-surface);
    font-size: .84rem;
}

.est-basis-title[b-e5lgy1aqvv] {
    font-weight: 650;
    color: var(--ft-navy);
    margin-bottom: .45rem;
}

.est-basis-facts[b-e5lgy1aqvv] {
    display: grid;
    grid-template-columns: fit-content(45%) minmax(0, 1fr);
    gap: .25rem .8rem;
    margin: 0;
}

.est-basis-facts dt[b-e5lgy1aqvv] {
    color: var(--ft-text-muted);
    overflow-wrap: anywhere;
}

.est-basis-facts dd[b-e5lgy1aqvv] {
    margin: 0;
    color: var(--ft-navy);
    font-variant-numeric: tabular-nums;
    overflow-wrap: anywhere;
}

.est-basis-hint[b-e5lgy1aqvv] {
    margin: 0;
    color: var(--ft-text-muted);
    line-height: 1.5;
}

.est-basis-actions[b-e5lgy1aqvv] {
    display: flex;
    flex-wrap: wrap;
    gap: .45rem;
    margin-top: .6rem;
}

.est-basis-btn[b-e5lgy1aqvv] {
    font-size: .78rem;
    padding: .25rem .7rem;
}

.est-basis-editor[b-e5lgy1aqvv] {
    margin-top: .6rem;
}

.est-basis-label[b-e5lgy1aqvv] {
    display: block;
    margin-top: .45rem;
    font-size: .78rem;
    color: var(--ft-text-muted);
}

.est-basis-input[b-e5lgy1aqvv] {
    display: block;
    width: 100%;
    margin-top: .2rem;
    padding: .35rem .5rem;
    border: 1px solid var(--ft-border-strong);
    border-radius: 6px;
    font: inherit;
    font-variant-numeric: tabular-nums;
}

.est-basis-error[b-e5lgy1aqvv] {
    margin-top: .5rem;
    color: var(--ft-danger-text, #b91c1c);
    font-size: .82rem;
}
/* /Components/Pages/Estimates/EstimateQuestions.razor.rz.scp.css */
/* ═══════════════════════════════════════════════════════════════════════════════════════════════
   The Questions step (AB#1773, Frame C), as a LAYOUT.

   Its own file, like every estimating surface since AB#1732: app.css is the one stylesheet three lanes
   would all have to edit to do UI at once, and a merge there breaks pages nobody touched.

   Colours are tokens, never literals, with the same fallbacks the workspace's own gate strip uses, so
   the two pages do not argue about what amber means and the dark theme comes free.

   What this file may be trusted with: layout and colour. bUnit never loads a stylesheet, so nothing
   here carries a claim a test has to see — the counts, the sentences and the links are all markup.
   ═══════════════════════════════════════════════════════════════════════════════════════════════ */

/* 1200px, the same as the workspace and the pack: the shell caps .ft-main-content at 1280px with
   2.5rem of padding each side, so 1200 is the whole of what is on offer. */
.eq[b-gyh2yuw693] {
    max-width: none;   /* AB#1773 W4: fluid; prose blocks keep their own 52rem measure */
}

.eq-pad[b-gyh2yuw693] {
    padding: 1rem 1.25rem;
}

.eq-muted[b-gyh2yuw693] {
    color: var(--ft-text-muted);
    line-height: 1.55;
}

/* ── the header: crumbs and the four-step journey on one row, then the bid ───────────────────── */
.eq-head[b-gyh2yuw693] {
    margin-bottom: 1rem;
}

.eq-head-top[b-gyh2yuw693] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: .5rem 1.25rem;
    margin-bottom: .35rem;
}

.eq-crumbs[b-gyh2yuw693] {
    display: flex;
    align-items: center;
    gap: .4rem;
    font-size: .8rem;
    color: var(--ft-text-faint);
    flex-wrap: wrap;
}

.eq-crumbs a[b-gyh2yuw693] {
    color: var(--ft-text-faint);
    text-decoration: none;
}

.eq-crumbs a:hover[b-gyh2yuw693] { color: var(--ft-primary); }

.eq-h1[b-gyh2yuw693] {
    margin: .2rem 0 .3rem;
    font-size: 1.4rem;
    font-weight: 700;
    letter-spacing: -.02em;
    color: var(--ft-navy);
    /* The client's own title is theirs and is never shortened; it wraps rather than pushing the
       page wider (the "text does not fit" complaint this ticket carries). */
    overflow-wrap: anywhere;
}

.eq-number[b-gyh2yuw693] {
    font-variant-numeric: tabular-nums;
}

.eq-dash[b-gyh2yuw693] {
    color: var(--ft-text-muted);
    font-weight: 500;
    margin: 0 .35rem;
}

.eq-meta[b-gyh2yuw693] {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    align-items: center;
    color: var(--ft-text-muted);
    font-size: .88rem;
}

/* ── the status line ───────────────────────────────────────────────────────────────────────────
   The same shape as the workspace's gate strip (AB#1751): a 3px edge in the state colour, and the
   sentence as ordinary text. Amber while there is work, green when the register is clear. */
.eq-strip[b-gyh2yuw693] {
    padding: .6rem .9rem;
    margin-bottom: 1rem;
    border-radius: 0 6px 6px 0;
    background: var(--ft-surface-2);
    font-size: .88rem;
    font-weight: 600;
    line-height: 1.5;
    color: var(--ft-navy);
}

.eq-strip.is-open[b-gyh2yuw693] {
    border-left: 3px solid var(--ft-amber, #f59e0b);
    color: var(--ft-amber-text, #b45309);
}

.eq-strip.is-clear[b-gyh2yuw693] {
    border-left: 3px solid var(--ft-green-text);
    color: var(--ft-green-text);
}

/* ── the cards ───────────────────────────────────────────────────────────────────────────────── */
.eq-card[b-gyh2yuw693] {
    padding: 1rem 1.25rem;
    margin-bottom: 1rem;
}

.eq-h2[b-gyh2yuw693] {
    margin: 0 0 .35rem;
    font-size: 1.05rem;
    font-weight: 650;
    color: var(--ft-navy);
}

.eq-h3[b-gyh2yuw693] {
    margin: 1rem 0 .4rem;
    font-size: .9rem;
    font-weight: 650;
    color: var(--ft-navy);
}

.eq-status[b-gyh2yuw693],
.eq-how[b-gyh2yuw693] {
    margin: 0 0 .9rem;
    color: var(--ft-text-muted);
    font-size: .9rem;
    line-height: 1.5;
    max-width: 52rem;
}

.eq-running[b-gyh2yuw693] {
    margin: 0 0 .9rem;
    color: var(--ft-text-muted);
    font-size: .9rem;
    display: flex;
    align-items: center;
    gap: .5rem;
}

.eq-failed[b-gyh2yuw693] {
    margin: 0 0 .9rem;
    color: var(--ft-amber-text, #b45309);
    font-size: .9rem;
}

/* AB#2445 — "Run again": a small link, with what a press costs written beside it. */
.eq-rerun[b-gyh2yuw693] {
    margin: -.4rem 0 .9rem;
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: .35rem .6rem;
    font-size: .85rem;
    max-width: 52rem;
}

.eq-rerun-link[b-gyh2yuw693] {
    background: none;
    border: 0;
    padding: 0;
    font: inherit;
    font-weight: 600;
    color: var(--ft-primary);
    text-decoration: underline;
    cursor: pointer;
}

.eq-rerun-link:disabled[b-gyh2yuw693] {
    color: var(--ft-text-muted);
    text-decoration: none;
    cursor: default;
}

.eq-rerun-hint[b-gyh2yuw693] {
    color: var(--ft-text-muted);
}

/* One question or one issue. The same block the rail drew, so a reader who learned the shape there
   finds it here — a left edge in the family colour, the sentence, and why it matters under it. */
.eq-item[b-gyh2yuw693] {
    padding: .7rem .85rem;
    margin-bottom: .5rem;
    background: var(--ft-surface-2);
    border-radius: 0 6px 6px 0;
    border-left: 3px solid var(--ft-border-strong);
}

.eq-item-ask[b-gyh2yuw693]   { border-left-color: var(--ft-primary); }
.eq-item-issue[b-gyh2yuw693] { border-left-color: var(--ft-amber, #f59e0b); }

.eq-item-what[b-gyh2yuw693] {
    font-weight: 600;
    color: var(--ft-navy);
    font-size: .92rem;
    line-height: 1.5;
    overflow-wrap: anywhere;
}

.eq-item-why[b-gyh2yuw693] {
    margin-top: .35rem;
    font-size: .85rem;
    color: var(--ft-text-muted);
    line-height: 1.5;
}

.eq-item-cite[b-gyh2yuw693] {
    margin-top: .25rem;
    font-size: .8rem;
    color: var(--ft-text-faint);
    line-height: 1.5;
}

.eq-label[b-gyh2yuw693] { font-weight: 600; }

.eq-row[b-gyh2yuw693] {
    font-variant-numeric: tabular-nums;
    color: var(--ft-text-muted);
}

.eq-row a[b-gyh2yuw693] {
    color: inherit;
    text-decoration: underline dotted;
}

.eq-item-actions[b-gyh2yuw693] {
    margin-top: .5rem;
    display: flex;
    flex-wrap: wrap;
    gap: .4rem;
}

.eq-action[b-gyh2yuw693] {
    font-size: .78rem;
    padding: .2rem .6rem;
    text-decoration: none;
}

/* ── the one primary exit ──────────────────────────────────────────────────────────────────── */
.eq-continue[b-gyh2yuw693] {
    display: flex;
    justify-content: flex-end;
    margin-bottom: 2rem;
}

/* ── AB#1850: an earlier answer offered to a re-worded question, and a row carried from a revision ── */
.eq-offer[b-gyh2yuw693] {
    margin-top: .6rem;
    padding: .6rem .75rem;
    border-radius: 6px;
    background: var(--ft-surface-2);
    border-left: 3px solid var(--ft-text-muted);
}

.eq-offer-what[b-gyh2yuw693] {
    font-size: .88rem;
    font-weight: 600;
    line-height: 1.45;
}

.eq-offer-meta[b-gyh2yuw693],
.eq-offer-why[b-gyh2yuw693] {
    margin-top: .25rem;
    font-size: .8rem;
    color: var(--ft-text-muted);
    line-height: 1.5;
    overflow-wrap: anywhere;
}

.eq-carried[b-gyh2yuw693] {
    margin-top: .35rem;
    font-size: .78rem;
    color: var(--ft-text-muted);
}

/* AB#1882 — the filters by answer source, the print link, and applying an answer to its line. */
.eq-filters[b-gyh2yuw693] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .35rem;
    margin: .6rem 0 .8rem;
}

.eq-filter[b-gyh2yuw693] {
    border: 1px solid var(--ft-border-strong);
    background: var(--ft-surface);
    color: var(--ft-text);
    border-radius: 999px;
    padding: .2rem .7rem;
    font-size: .8rem;
    cursor: pointer;
}

.eq-filter:hover[b-gyh2yuw693] { border-color: var(--ft-navy); }

.eq-filter.is-on[b-gyh2yuw693] {
    background: var(--ft-navy);
    border-color: var(--ft-navy);
    color: var(--ft-on-navy, #fff);
}

.eq-print[b-gyh2yuw693] { margin-left: auto; }

.eq-apply[b-gyh2yuw693] { margin-top: .5rem; }

.eq-apply-form[b-gyh2yuw693] {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: .5rem;
    padding: .5rem .6rem;
    border-radius: 8px;
    background: var(--ft-surface-2);
    font-size: .82rem;
}

.eq-apply-form > .eq-muted[b-gyh2yuw693] { flex-basis: 100%; }

.eq-apply-form label[b-gyh2yuw693] {
    display: flex;
    flex-direction: column;
    gap: .15rem;
}

.eq-apply-form input[b-gyh2yuw693] { width: 8rem; }

.eq-apply-outcome[b-gyh2yuw693] {
    margin-top: .35rem;
    font-size: .8rem;
    color: var(--ft-text-muted);
}
/* /Components/Pages/Estimates/EstimateRevisionReason.razor.rz.scp.css */
/* AB#2280 — the workspace's own rule for this sentence (EstimateWorkspace.razor.css, .est-revision-reason), moved with it:
   scoped CSS does not reach into a child component. */
.est-revision-reason[b-p84472wijb] {
    margin: .35rem 0 0;
    font-size: .85rem;
    color: var(--ft-text-muted);
}
/* /Components/Pages/Estimates/Estimates.razor.rz.scp.css */
/* AB#1773 (frame A) — the estimates list.
 *
 * SCOPED: Blazor CSS isolation rewrites every selector here with this component's own attribute, so nothing
 * in this file reaches another page and app.css is not touched — the seam that lets three lanes do UI at
 * once. Until this file existed the page was styled inline, which is fine for a card with two lines and
 * wrong for the claims this ticket makes: "a row never wraps" and "a long title ellipsises" are rules a test
 * has to be able to read back off a stylesheet, and an inline style cannot be asserted from one.
 *
 * COLOURS ARE --ft-* TOKENS and set with the LONGHAND, never the `background` shorthand: EstimatesListTests
 * resolves these rules through AngleSharp.Css, which returns empty for a var() inside the shorthand
 * (measured for RevisionCompare.razor.css; same engine, same rule).
 */

.el[b-25pxuf50zi] { max-width: none; }   /* AB#1773 W4: fluid */

.el-head[b-25pxuf50zi] {
    display: flex;
    align-items: flex-start;
    gap: 1rem;
}

.el-head-text[b-25pxuf50zi] { flex: 1; min-width: 0; }

.el-h1[b-25pxuf50zi] {
    margin: 0 0 .35rem;
    font-size: 1.4rem;
    font-weight: 700;
    color: var(--ft-navy);
}

.el-sub[b-25pxuf50zi] {
    margin: 0 0 1.25rem;
    color: var(--ft-text-muted);
    font-size: .92rem;
    line-height: 1.5;
}

.el-loading[b-25pxuf50zi] { padding: 1rem; }

.el-empty[b-25pxuf50zi] {
    padding: 1.5rem;
    color: var(--ft-text-muted);
    line-height: 1.55;
}

/* ── one row ─────────────────────────────────────────────────────────────────────────────────── */

/* The row is a flex line and NEVER wraps: the text block shrinks (min-width:0 is what lets it) and the
   actions keep their width. A long title therefore takes what is left and ellipsises inside .el-title,
   rather than pushing the buttons onto a second line — which is what the old inline `flex-wrap:wrap` did
   the moment a title and three buttons did not fit. */
.el-row[b-25pxuf50zi] {
    padding: .85rem 1rem;
    margin-bottom: .6rem;
    display: flex;
    align-items: center;
    gap: 1rem;
    flex-wrap: nowrap;
}

/* AB#1873: the text block keeps a floor so the pipeline columns beside it cannot squeeze the bid's number and
   title to nothing; below that the table scrolls sideways INSIDE its own box (.el-grid), never the page. */
.el-main[b-25pxuf50zi] { flex: 1 1 auto; min-width: 14rem; }

.el-line1[b-25pxuf50zi] {
    display: flex;
    align-items: center;
    gap: .5rem;
    min-width: 0;
    white-space: nowrap;
}

.el-number[b-25pxuf50zi] {
    flex: 0 0 auto;
    color: var(--ft-navy);
    font-variant-numeric: tabular-nums;
}

/* Ellipsis, with the whole title in the element's title attribute — frame A's "long titles ellipsize with
   tooltip".

   AB#2184 — ON A LINE OF ITS OWN, UP TO TWO LINES. It used to share one nowrap line with the number and the
   revision/option badges, which left it ~115 px at 1280: measured on the loaded RCG list, 47 of 62 titles were
   cut at 1280 and 37 of 62 at 1440 — three option rows of one bid all read "25-174 1000…". Now the number and
   badges keep line one and the title is its own block under them (Estimates.razor), at most two lines: 4 of 62
   cut at either width, for ~18 px more per row. The ROW still never wraps (the actions stay on the right); only
   this text does. */
.el-title[b-25pxuf50zi] {
    margin-top: .15rem;
    min-width: 0;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: normal;
    color: var(--ft-navy);
}

/* Which revision this is (frame A's REV column). Quiet — a fact, not a state. */
.el-rev[b-25pxuf50zi] {
    flex: 0 0 auto;
    padding: 1px 7px;
    border-radius: 20px;
    border: 1px solid var(--ft-border);
    background-color: var(--ft-surface-2);
    color: var(--ft-text-muted);
    font-size: .7rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    letter-spacing: .02em;
}

/* Which priced OPTION this row is (AB#1789). Louder than the revision pill on purpose: on a tiered bid it is
   the ONLY thing that tells three otherwise identical rows apart, where the revision pill is a fact you
   already knew. Not truncated — "Like for like" and "Like for like (partial)" are different scopes and a cut
   name would merge them on sight. */
.el-tier[b-25pxuf50zi] {
    flex: 0 0 auto;
    padding: 1px 8px;
    border-radius: 20px;
    border: 1px solid var(--ft-primary);
    background-color: var(--ft-surface);
    color: var(--ft-primary);
    font-size: .7rem;
    font-weight: 700;
    letter-spacing: .02em;
}

.el-line2[b-25pxuf50zi] {
    margin-top: .25rem;
    color: var(--ft-text-muted);
    font-size: .85rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.el-unpriced[b-25pxuf50zi] { color: var(--ft-amber-text); }

/* ── the actions: Open primary, Compare secondary, Pack tertiary, in that order on every row ──── */

.el-actions[b-25pxuf50zi] {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: .5rem;
}

/* Pack is the third thing, visually: no fill, no border, muted text, and it earns an underline on hover.
   ft-btn gives it the size and the click target; this takes the emphasis away. */
.el-tertiary[b-25pxuf50zi] {
    background-color: transparent;
    border: 1px solid transparent;
    color: var(--ft-text-muted);
    box-shadow: none;
}

.el-tertiary:hover[b-25pxuf50zi] {
    background-color: var(--ft-surface-2);
    color: var(--ft-text);
    text-decoration: underline;
}

@media (max-width: 640px) {
    .el-row[b-25pxuf50zi] { align-items: flex-start; }
    .el-actions[b-25pxuf50zi] { flex-direction: column; align-items: stretch; }
}

/* ── AB#1834: search, filter and sort ─────────────────────────────────────────────────────────── */

/* The toolbar WRAPS, unlike a row: it is controls, not a line of text, and at a narrow width a control
   pushed onto a second line is still usable where a clipped one is not. */
.el-tools[b-25pxuf50zi] {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: .6rem 1rem;
    margin-bottom: .9rem;
}

.el-tool[b-25pxuf50zi] {
    display: flex;
    flex-direction: column;
    gap: .25rem;
    margin: 0;
    font-size: .85rem;
}

.el-tool-search[b-25pxuf50zi] { flex: 1 1 16rem; min-width: 12rem; }

.el-tool-label[b-25pxuf50zi] {
    color: var(--ft-text-muted);
    font-size: .75rem;
    font-weight: 600;
}

.el-tool-check[b-25pxuf50zi] {
    flex-direction: row;
    align-items: center;
    gap: .4rem;
    padding-bottom: .45rem;
}

.el-tool-count[b-25pxuf50zi] {
    color: var(--ft-text-muted);
    font-size: .85rem;
    padding-bottom: .45rem;
}

/* ── AB#1873: the pipeline ────────────────────────────────────────────────────────────────────── */

/* The KPI strip: six tiles that wrap, never shrink below a readable width. The first three are BUTTONS (each
   opens its view); the rest are facts. */
.el-kpis[b-25pxuf50zi] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(9.5rem, 1fr));
    gap: .75rem;
    margin-bottom: .9rem;
}

.el-kpi[b-25pxuf50zi] {
    display: flex;
    flex-direction: column;
    gap: .3rem;
    padding: .75rem .9rem;
    border: 1px solid var(--ft-card-border);
    border-radius: var(--ft-radius);
    background-color: var(--ft-surface);
    text-align: left;
    font: inherit;
    color: var(--ft-text);
}

button.el-kpi[b-25pxuf50zi] { cursor: pointer; }
button.el-kpi:hover[b-25pxuf50zi] { border-color: var(--ft-primary); }

.el-kpi-label[b-25pxuf50zi] {
    color: var(--ft-text-muted);
    font-size: .7rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
}

.el-kpi-value[b-25pxuf50zi] {
    color: var(--ft-navy);
    font-size: 1.45rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.el-kpi-warn[b-25pxuf50zi] { color: var(--ft-amber-text); }
.el-kpi-bad[b-25pxuf50zi] { color: var(--ft-red-text); }
.el-kpi-good[b-25pxuf50zi] { color: var(--ft-green-text); }
.el-kpi-none[b-25pxuf50zi] { color: var(--ft-text-faint); }

/* AB#2182 — the own-year count, directly under the strip it qualifies. */
.el-kpi-note[b-25pxuf50zi] {
    margin: -.4rem 0 .9rem;
    color: var(--ft-text-muted);
    font-size: .82rem;
    line-height: 1.45;
}

/* The follow-ups due and the lost-without-a-reason callout sit ABOVE the table rather than beside it (mock-up 08
   draws them in a right-hand column): the table needs the width for its columns, and a panel squeezed beside
   eight of them would be the first thing to wrap. */
.el-asides[b-25pxuf50zi] {
    display: flex;
    flex-wrap: wrap;
    gap: .75rem;
    margin-bottom: .9rem;
}

.el-aside[b-25pxuf50zi] {
    flex: 1 1 22rem;
    padding: .85rem 1rem;
}

.el-aside-callout[b-25pxuf50zi] {
    flex: 0 1 22rem;
    border-left: 3px solid var(--ft-orange);
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: .5rem;
}

.el-aside-h[b-25pxuf50zi] {
    margin: 0 0 .5rem;
    font-size: .95rem;
    font-weight: 700;
    color: var(--ft-navy);
}

.el-aside-none[b-25pxuf50zi], .el-aside-rule[b-25pxuf50zi], .el-callout-text[b-25pxuf50zi] {
    margin: 0;
    color: var(--ft-text-muted);
    font-size: .82rem;
    line-height: 1.45;
}

.el-callout-text[b-25pxuf50zi] { color: var(--ft-text); font-size: .88rem; }

.el-aside-rule[b-25pxuf50zi] { margin-top: .5rem; }

.el-followups[b-25pxuf50zi] {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: .3rem;
}

.el-followups li[b-25pxuf50zi] {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    font-size: .85rem;
}

.el-followup-bid[b-25pxuf50zi] {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--ft-text);
}

.el-followup-when[b-25pxuf50zi] { flex: 0 0 auto; color: var(--ft-text-muted); }

/* The views: a mode, drawn as a row of pills with the chosen one filled. */
.el-views[b-25pxuf50zi] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .4rem;
    margin-bottom: .75rem;
}

.el-view[b-25pxuf50zi] {
    padding: .3rem .75rem;
    border: 1px solid var(--ft-border);
    border-radius: 20px;
    background-color: var(--ft-surface);
    color: var(--ft-text);
    font: inherit;
    font-size: .85rem;
    cursor: pointer;
}

.el-view-on[b-25pxuf50zi] {
    border-color: var(--ft-primary);
    background-color: var(--ft-primary);
    color: #fff;
    font-weight: 600;
}

.el-saved[b-25pxuf50zi] { margin-left: auto; color: var(--ft-text-faint); font-size: .75rem; }

/* The table: rows are the frame-A flex line (.el-row, which never wraps), with fixed-width pipeline cells
   between the bid and its actions. Below the width they need, THIS box scrolls sideways — the page does not. */
.el-grid[b-25pxuf50zi] { overflow-x: auto; }

.el-grid > .el-row[b-25pxuf50zi] { min-width: 64rem; }

.el-colhead[b-25pxuf50zi] {
    padding-top: .25rem;
    padding-bottom: .25rem;
    margin-bottom: .35rem;
    align-items: flex-end;
}

.el-sort[b-25pxuf50zi] {
    padding: 0;
    border: 0;
    background-color: transparent;
    color: var(--ft-text-muted);
    font: inherit;
    font-size: .7rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    cursor: pointer;
    text-align: left;
}

.el-sort:hover[b-25pxuf50zi] { color: var(--ft-text); text-decoration: underline; }
.el-sort-sub[b-25pxuf50zi] { display: block; margin-top: .15rem; font-weight: 600; }

.el-actions-head[b-25pxuf50zi] { visibility: hidden; min-height: 1px; }

.el-cell[b-25pxuf50zi] {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    gap: .2rem;
    min-width: 0;
    font-size: .85rem;
}

.el-c-status[b-25pxuf50zi] { width: 9.5rem; }
.el-c-due[b-25pxuf50zi] { width: 7rem; }
.el-c-offer[b-25pxuf50zi] { width: 8rem; }
.el-c-outcome[b-25pxuf50zi] { width: 7.5rem; }

/* The actions keep ONE width in the header and every row, so the columns line up. */
.el-actions[b-25pxuf50zi] { width: 20rem; justify-content: flex-end; }

.el-stage-line[b-25pxuf50zi] { display: flex; align-items: center; gap: .35rem; }

.el-status[b-25pxuf50zi] {
    flex: 0 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.el-stage-won[b-25pxuf50zi] { color: var(--ft-green-text); background-color: var(--ft-green-bg); }
.el-stage-closed[b-25pxuf50zi] { color: var(--ft-text-muted); background-color: var(--ft-surface-2); }
.el-stage-out[b-25pxuf50zi] { color: var(--ft-blue-text); background-color: var(--ft-blue-bg); }
.el-stage-unknown[b-25pxuf50zi] { color: var(--ft-amber-text); background-color: var(--ft-amber-bg); }

.el-lock[b-25pxuf50zi] { flex: 0 0 auto; display: inline-flex; color: var(--ft-text-muted); }

.el-next[b-25pxuf50zi] {
    align-self: flex-start;
    padding: 1px 8px;
    border: 1px solid var(--ft-border);
    border-radius: 20px;
    color: var(--ft-text);
    font-size: .75rem;
    white-space: nowrap;
}

.el-late[b-25pxuf50zi] { color: var(--ft-red-text); border-color: var(--ft-red); }
.el-today[b-25pxuf50zi] { color: var(--ft-red-text); font-weight: 600; }
.el-soon[b-25pxuf50zi] { color: var(--ft-amber-text); }

.el-due-date[b-25pxuf50zi] { color: var(--ft-text); }
.el-due-rel[b-25pxuf50zi] { color: var(--ft-text-muted); font-size: .78rem; }

.el-proposal[b-25pxuf50zi] { color: var(--ft-text); font-variant-numeric: tabular-nums; }

.el-sentvia[b-25pxuf50zi] { display: flex; flex-wrap: wrap; gap: .25rem; }

.el-chip[b-25pxuf50zi] {
    padding: 0 6px;
    border: 1px solid var(--ft-border);
    border-radius: 20px;
    color: var(--ft-text-muted);
    font-size: .72rem;
}

.el-outcome[b-25pxuf50zi] { font-weight: 600; }
.el-outcome-won[b-25pxuf50zi] { color: var(--ft-green-text); }
.el-outcome-lost[b-25pxuf50zi] { color: var(--ft-red-text); }
.el-decided[b-25pxuf50zi], .el-awaiting[b-25pxuf50zi] { color: var(--ft-text-muted); font-size: .78rem; }
.el-noreason[b-25pxuf50zi] { color: var(--ft-red-text); font-size: .75rem; }
.el-none[b-25pxuf50zi] { color: var(--ft-text-faint); }

/* Below 1400px the four actions take two lines of two — Open and Compare, then Pack and History — in the SAME
   order (Mark's call is the order, AB#1773). Measured at 1280: on one line they pushed History out of the
   table's box and behind a sideways scroll, the AB#1802 shape; on two they fit, and the row itself still never
   wraps. */
@media (max-width: 1399px) {
    .el-actions[b-25pxuf50zi] { width: 11.5rem; flex-wrap: wrap; justify-content: flex-start; row-gap: .35rem; }
    .el-grid > .el-row[b-25pxuf50zi] { min-width: 56rem; }
}

.el-owner[b-25pxuf50zi] {
    margin-top: .15rem;
    color: var(--ft-text-muted);
    font-size: .78rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
/* /Components/Pages/Estimates/EstimateSiteLocationBadge.razor.rz.scp.css */
/* AB#2197 — the site-location chip. Tokens declared in BOTH themes only (--ft-green/amber/red + their -bg/-text). */
.est-site-location[b-tjvx7y5ijp] {
    display: inline-block;
    margin-left: .4rem;
    padding: .05rem .45rem;
    border-radius: 999px;
    font-size: .75rem;
    line-height: 1.4;
    white-space: nowrap;
    vertical-align: baseline;
    cursor: help;
}

.est-site-location--located[b-tjvx7y5ijp] {
    background: var(--ft-green-bg);
    color: var(--ft-green-text);
}

.est-site-location--approximate[b-tjvx7y5ijp] {
    background: var(--ft-amber-bg);
    color: var(--ft-amber-text);
}

.est-site-location--not-located[b-tjvx7y5ijp] {
    background: var(--ft-red-bg);
    color: var(--ft-red-text);
}
/* /Components/Pages/Estimates/EstimateSteps.razor.rz.scp.css */
/* ═══════════════════════════════════════════════════════════════════════════════════════════════
   The four-step indicator (AB#1735).

   Its own file, like every other estimating surface since AB#1732: app.css is the one file three lanes
   would all have to edit to do UI at once, and a merge there breaks pages nobody touched.

   Colours are tokens, never literals. The light palette in app.css already IS the wireframe's palette —
   --ft-primary resolves to #2d6be4 in light mode, which is the exact blue on artboard 03 — so the dark
   theme comes free and a hard-coded hex would have looked right in the screenshot and wrong at night.
   ═══════════════════════════════════════════════════════════════════════════════════════════════ */

.est-steps[b-btefn7jivu] {
    display: flex;
    align-items: center;
    gap: 1.375rem;
    flex-wrap: wrap;
}

/* The whole step is the target, not just the label — a 22px circle is under the 24px minimum a finger
   can reliably hit, and the number is the part a reader points at. */
.est-step[b-btefn7jivu] {
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    font-size: .83rem;
    font-weight: 600;
    line-height: 1.2;
    color: var(--ft-text-faint);
    text-decoration: none;
    padding: .2rem 0;
    min-height: 1.75rem;
}

.est-step:hover[b-btefn7jivu] { color: var(--ft-text); }

.est-step-n[b-btefn7jivu] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.375rem;
    height: 1.375rem;
    flex: 0 0 auto;
    border-radius: 50%;
    border: 1px solid var(--ft-border);
    font-size: .72rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

/* The step you are on. Fill AND colour, not colour alone: the numeral inside a filled disc still reads
   as "you are here" on a monochrome screen and to a reader who cannot separate the two blues. */
.est-step.is-current[b-btefn7jivu] {
    color: var(--ft-primary);
}

.est-step.is-current .est-step-n[b-btefn7jivu] {
    background: var(--ft-primary);
    border-color: var(--ft-primary);
    color: #fff;
}

/* Under the shell's own breakpoint the header stacks, and four steps across a phone would wrap into a
   ragged block. The numbers alone still carry the position. */
@media (max-width: 700px) {
    .est-steps[b-btefn7jivu] { gap: .75rem; }
    .est-step-label[b-btefn7jivu] { display: none; }
}
/* /Components/Pages/Estimates/EstimateTakeoffPanel.razor.rz.scp.css */
/* AB#1669 — the takeoff table in the rail. Tokens only (declared in both themes), so the dark theme comes free; the
   shape follows the quantity-basis card directly above it. */
.est-takeoff[b-xsoqxhvx7x] {
    margin-top: .8rem;
    padding: .75rem .9rem;
    border: 1px solid var(--ft-border);
    border-radius: 6px;
    background: var(--ft-surface);
    font-size: .84rem;
}

.est-takeoff-title[b-xsoqxhvx7x] {
    font-weight: 650;
    color: var(--ft-navy);
    margin-bottom: .45rem;
}

.est-takeoff-derivation[b-xsoqxhvx7x] {
    margin: 0 0 .3rem;
    color: var(--ft-navy);
    font-variant-numeric: tabular-nums;
    overflow-wrap: anywhere;
    line-height: 1.5;
}

.est-takeoff-result[b-xsoqxhvx7x] {
    margin: 0 0 .5rem;
    font-weight: 600;
    color: var(--ft-navy);
    font-variant-numeric: tabular-nums;
}

.est-takeoff-waiting[b-xsoqxhvx7x] {
    padding: .35rem .5rem;
    border-radius: 6px;
    background: var(--ft-amber-bg);
    color: var(--ft-amber-text);
    font-weight: 500;
}

.est-takeoff-hint[b-xsoqxhvx7x] {
    margin: 0;
    color: var(--ft-text-muted);
    line-height: 1.5;
}

.est-takeoff-term[b-xsoqxhvx7x] {
    margin-top: .5rem;
    padding-left: .6rem;
    border-left: 2px solid var(--ft-border-strong);
}

.est-takeoff-term[data-sign="Deduct"][b-xsoqxhvx7x] {
    border-left-color: var(--ft-amber);
}

.est-takeoff-term-head[b-xsoqxhvx7x] {
    font-size: .76rem;
    font-weight: 600;
    color: var(--ft-text-muted);
    text-transform: uppercase;
    letter-spacing: .02em;
    overflow-wrap: anywhere;
}

.est-takeoff-factor[b-xsoqxhvx7x] {
    padding: .35rem 0;
    border-bottom: 1px solid var(--ft-border);
}

.est-takeoff-factor:last-child[b-xsoqxhvx7x] {
    border-bottom: 0;
}

.est-takeoff-figure[b-xsoqxhvx7x] {
    display: flex;
    justify-content: space-between;
    gap: .6rem;
    color: var(--ft-navy);
}

.est-takeoff-name[b-xsoqxhvx7x] {
    overflow-wrap: anywhere;
}

.est-takeoff-value[b-xsoqxhvx7x] {
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    font-weight: 600;
}

.est-takeoff-source[b-xsoqxhvx7x] {
    margin-top: .15rem;
    font-size: .78rem;
    color: var(--ft-text-muted);
    overflow-wrap: anywhere;
}

.est-takeoff-kind[b-xsoqxhvx7x] {
    font-weight: 600;
    margin-right: .3rem;
}

.est-takeoff-approx[b-xsoqxhvx7x] {
    margin-top: .2rem;
    font-size: .76rem;
    color: var(--ft-amber-text);
    font-weight: 600;
}

.est-takeoff-confirmed[b-xsoqxhvx7x] {
    margin-top: .2rem;
    font-size: .76rem;
    color: var(--ft-text-muted);
}

.est-takeoff-actions[b-xsoqxhvx7x] {
    display: flex;
    flex-wrap: wrap;
    gap: .45rem;
    margin-top: .45rem;
}

.est-takeoff-btn[b-xsoqxhvx7x] {
    font-size: .78rem;
    padding: .25rem .7rem;
}

.est-takeoff-link[b-xsoqxhvx7x] {
    margin-top: .5rem;
    padding: 0;
    border: 0;
    background: none;
    color: var(--ft-accent);
    font: inherit;
    font-size: .78rem;
    cursor: pointer;
}

.est-takeoff-history[b-xsoqxhvx7x] {
    margin: .35rem 0 0;
    padding-left: 1.1rem;
    font-size: .78rem;
    color: var(--ft-text-muted);
    overflow-wrap: anywhere;
}

.est-takeoff-when[b-xsoqxhvx7x] {
    font-variant-numeric: tabular-nums;
    margin-right: .35rem;
}

.est-takeoff-editor[b-xsoqxhvx7x] {
    margin-top: .6rem;
}

.est-takeoff-row[b-xsoqxhvx7x] {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: .5rem;
}

.est-takeoff-label[b-xsoqxhvx7x] {
    display: block;
    margin-top: .45rem;
    font-size: .78rem;
    color: var(--ft-text-muted);
}

.est-takeoff-check[b-xsoqxhvx7x] {
    display: flex;
    gap: .4rem;
    align-items: flex-start;
    margin-top: .5rem;
    font-size: .78rem;
    color: var(--ft-text-muted);
}

.est-takeoff-input[b-xsoqxhvx7x] {
    display: block;
    width: 100%;
    margin-top: .2rem;
    padding: .35rem .5rem;
    border: 1px solid var(--ft-border-strong);
    border-radius: 6px;
    font: inherit;
    font-variant-numeric: tabular-nums;
}

.est-takeoff-error[b-xsoqxhvx7x] {
    margin-top: .5rem;
    color: var(--ft-danger-text, #b91c1c);
    font-size: .82rem;
}
/* /Components/Pages/Estimates/EstimateUnknownsPanel.razor.rz.scp.css */
/* ═══════════════════════════════════════════════════════════════════════════════════════════════
   The unknowns register (AB#1652), and specifically the CONFLICT card's compact summary (AB#1814).

   WHY THIS FILE IS PARTIAL, AND DELIBERATELY SO. Every other rule in this panel is still an inline
   `style` attribute, written before estimating surfaces had scoped stylesheets. AB#1814 is a change to
   the conflict card and nothing else, so it brings its own markup and its own classes, and it does NOT
   restyle the entries beside it: a wholesale inline-to-scoped conversion of a component two pages render
   is a change whose blast radius is the whole register, on a ticket about three lines of summary. The
   remaining conversion is worth doing and is not this ticket.

   It is a `.razor.css` and not `app.css` for the reason every estimating surface has had one since
   AB#1732: `app.css` is the one stylesheet three lanes would all have to edit to do UI at once, and a
   merge there breaks pages nobody touched.

   WHAT THIS FILE MAY BE TRUSTED WITH: layout and colour. bUnit loads no stylesheet, so nothing here
   carries a claim a test has to see — and one rule below (`.uk-clamp`) HIDES text that is still in the
   DOM, which is precisely the shape no component test can observe. Every character it clamps is also on
   the element's `title`, per the tooltip standard (AB#1811), and the clamp is verified in a browser.
   ═══════════════════════════════════════════════════════════════════════════════════════════════ */

/* ── the conflict card ─────────────────────────────────────────────────────────────────────────
   Same shape the inline rules drew — a danger-coloured left edge on an inset well — so a reader who
   learned the register before this ticket still recognises it.

   `--ft-red-text` and NOT `var(--ft-danger,#dc2626)`: --ft-danger is declared in neither theme, so the
   old inline rule has always painted the hard-coded light-theme red, on a dark card at night included.
   --ft-red-text is declared in both (#b42318 light, #ff6e77 dark). */
.uk-conflict[b-bjr6icnc1n] {
    padding: .7rem .85rem;
    margin-bottom: .5rem;
    border-left: 3px solid var(--ft-red-text);
    background: var(--ft-surface-2);
    border-radius: 0 6px 6px 0;
}

/* ── the originating line, above everything ───────────────────────────────────────────────────
   The item code never shrinks — it is what an estimator types into their own workbook to find the row.
   The description is the customer's own words and is clamped to one line with the whole string on
   `title`; it is context, and a forty-word description would push the summary off the first screen. */
.uk-conflict-origin[b-bjr6icnc1n] {
    display: flex;
    align-items: baseline;
    gap: .4rem;
    margin-bottom: .35rem;
    font-size: .8rem;
    color: var(--ft-text-muted);
    min-width: 0;
}

.uk-conflict-item[b-bjr6icnc1n] {
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    white-space: nowrap;
    flex: 0 0 auto;
}

.uk-conflict-desc[b-bjr6icnc1n] {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ── the compact summary: three labelled facts ────────────────────────────────────────────────
   A two-column grid on anything with room, so the three labels line up and the eye runs down the
   values. The label column is sized in `ch` off the longest label rather than a guessed rem, because
   German ("Vorgeschlagene Behandlung") is half again as long as English and a rem that fits one wraps
   the other.

   Under 34rem — a narrow window, or the panel inside the workspace rail — it stacks: a 14ch label
   column beside a value on a 320px screen leaves the value four words wide. */
.uk-sum[b-bjr6icnc1n] {
    margin: 0 0 .45rem;
    display: grid;
    gap: .25rem .75rem;
    font-size: .85rem;
    line-height: 1.5;
}

.uk-sum-row[b-bjr6icnc1n] {
    display: grid;
    grid-template-columns: minmax(9rem, 12rem) 1fr;
    gap: .25rem .75rem;
    align-items: baseline;
}

.uk-sum dt[b-bjr6icnc1n] {
    margin: 0;
    font-size: .74rem;
    font-weight: 700;
    letter-spacing: .02em;
    text-transform: uppercase;
    color: var(--ft-text-faint);
}

.uk-sum dd[b-bjr6icnc1n] {
    margin: 0;
    color: var(--ft-navy);
    font-weight: 500;
    overflow-wrap: anywhere;
}

@media (max-width: 34rem) {
    .uk-sum-row[b-bjr6icnc1n] {
        grid-template-columns: 1fr;
        gap: 0;
    }
}

/* ── the two long sentences, under the summary ────────────────────────────────────────────────
   `.uk-conflict-lead` is the card WITHOUT a summary: the sentences are then the only thing on it and
   are never clamped. `.uk-conflict-prose` is the card with one: demoted to the muted size, and clamped
   to three lines with the whole string on `title`. */
.uk-conflict-lead[b-bjr6icnc1n] {
    font-weight: 600;
    color: var(--ft-navy);
    font-size: .9rem;
    line-height: 1.5;
}

.uk-conflict-prose[b-bjr6icnc1n] {
    font-size: .82rem;
    color: var(--ft-text-muted);
    line-height: 1.5;
    max-width: 60rem;
}

/* THE ONE RULE ON THIS PAGE THAT HIDES TEXT. Every character it hides is on the element's `title`,
   which is the tooltip standard (AB#1811) and the only reason a clamp is allowed here at all.

   MEASURED, because a clamp is exactly the kind of rule that can be inert and look fine. On the running
   Dashboard (Chrome 152) `getComputedStyle(el).display` on this element reports **flow-root**, not
   `-webkit-box` — the browser blockifies it under its newer line-clamp implementation — so reading the
   computed display is NOT a way to tell whether this works. It does work: setting
   `-webkit-line-clamp: 1` in the same session took the element from 55px to 18px, and at 390px wide the
   full text measures 129px against 55px shown. `line-clamp: 3` is the standard property and
   `CSS.supports('line-clamp','3')` is FALSE in that build, so today it is a dead declaration kept for
   the version that honours it; the `-webkit-` pair is what is actually clamping. */
.uk-clamp[b-bjr6icnc1n] {
    display: -webkit-box;
    -webkit-line-clamp: 3;
    line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.uk-conflict-cta[b-bjr6icnc1n] {
    margin-top: .5rem;
    font-size: .78rem;
    padding: .2rem .6rem;
}
/* /Components/Pages/Estimates/EstimateWorkspace.razor.rz.scp.css */
/* ═══════════════════════════════════════════════════════════════════════════════════════════════
   The estimating workspace, as a LAYOUT (AB#1732), re-orchestrated so it tells ONE story (AB#1773 W1).

   Why this file exists at all. Before it there was not one estimating-specific rule in the solution —
   `grep -c 'estimate-' wwwroot/app.css` returned 0 — and the page was nine generic cards stacked
   full-width in one column, 6,252 px tall at 1440. Every batch from F to M made a capability REACHABLE
   by appending another card, which was right each time; reachability accretes and layout does not.

   Why a `.razor.css` and not `app.css`. app.css is the one file three lanes would all have to edit to
   do UI at once, and a merge there breaks pages nobody touched. Blazor's scoped CSS gives this page its
   own file that cannot reach any other page — the isolation is the point, not a side effect.

   WHAT THIS FILE MAY AND MAY NOT BE TRUSTED WITH. bUnit never loads a stylesheet, so a rule that gets
   swallowed here is invisible to every component test. So the rules that carry an AFFORDANCE — the
   thing that tells an estimator a cell can be typed in — deliberately stay as inline style in the
   markup, where the computed style IS the markup and a test can read it (see `EditableCellStyle`).
   What lives here is LAYOUT and COLOUR, where the failure mode of a swallowed rule is a page that
   looks like the old one rather than a page that lies about what you can do. The one exception is the
   description clamp and the column weights below, which a browser test reads back as computed style
   (EstimateWorkspaceTextFitsTests) because "the text fits" is Mark's complaint and no DOM count can
   see whether it does.

   Colours are tokens, never literals. The light palette in app.css already IS the wireframe's palette
   — --ft-green-bg is #e6f4ec and the mockup's price-book chip is #e6f4ec — so the whole colour scheme
   below costs nothing and the dark theme comes free. A hard-coded hex here would have looked right in
   the screenshot and wrong at night.
   ═══════════════════════════════════════════════════════════════════════════════════════════════ */

/* ── the page ──────────────────────────────────────────────────────────────────────────────────
   1200px, not 1180. The shell caps .ft-main-content at 1280px with 2.5rem of padding each side, so
   1200 is the whole of what is on offer and anything larger silently does nothing. */
.est-page[b-h5mwmolj4w] {
    max-width: none;   /* AB#1773 W4 (Mark, 9 Sep): the page uses the window; the grid takes what the rail leaves */
}

/* ── the back link and the four-step journey, on one row (AB#1749) ─────────────────────────────
   WHY THEY SHARE A ROW rather than stacking. Both are "where am I and how do I leave", and the
   header below them is "which bid is this". Two rows for one question would push the bid number —
   the thing an estimator scans for — a line further down every screen for no gain.

   `space-between` and not a grid: the stepper is `EstimateSteps`'s own markup and its scoped CSS
   owns everything inside it. This file positions the BOX and nothing within it, which is what keeps
   two components' stylesheets from having an opinion about the same element. */
.est-head-top[b-h5mwmolj4w] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: .5rem 1.25rem;
    margin-bottom: .15rem;
}

/* The compare entry beside the revision chip (AB#1773 W1). History left the rail — it is bid-level,
   not line-level — so the header carries the one-word way to the compare screen, the same word the
   estimates list uses for the same door. */
.est-head-compare[b-h5mwmolj4w] {
    font-size: .85rem;
    font-weight: 600;
    color: var(--ft-primary);
    text-decoration: underline;
    text-underline-offset: 2px;
}

/* ── Submit, and the reasons it cannot be pressed (AB#1810) ────────────────────────────────────
   THE LIST IS UNDER THE BUTTON AND RIGHT-ALIGNED WITH IT, which is the only placement that reads as
   "these belong to that control". The header row it sits in is `flex-wrap` prose — client name, site
   address — so the group is a column of its own and the row inside it keeps the button and the
   save error on one line exactly as they were.

   `margin-left:auto` moved off the inline style and onto this class. It was doing the same job there;
   it is here because the element is now two rows and the alignment belongs with the rest of them.

   NOT AMBER-FILLED, and not a card. It sits one row above a strip whose whole left edge is already the
   gate's amber, and a second filled amber block would make the header and the strip compete to be the
   warning. Muted text at .78rem is enough: the reader has already been stopped by the disabled button
   and is looking for why, not for an alarm. */
.est-submit-group[b-h5mwmolj4w] {
    margin-left: auto;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: .3rem;
}

.est-submit-row[b-h5mwmolj4w] {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    align-items: center;
}

.est-submit-why[b-h5mwmolj4w] {
    margin: 0;
    padding: 0;
    list-style: none;
    text-align: right;
    font-size: .78rem;
    line-height: 1.45;
    color: var(--ft-amber-text, #b45309);
    max-width: 22rem;
}

/* At a narrow width the header stacks and `flex-end` would push the reasons off to the right of a
   left-aligned page. 700px is where .est-head-top already wraps. */
@media (max-width: 700px) {
    .est-submit-group[b-h5mwmolj4w] {
        margin-left: 0;
        align-items: flex-start;
    }

    .est-submit-why[b-h5mwmolj4w] { text-align: left; }
}

/* ── one progress story (AB#1751, and the top of the page's story since AB#1773 W1) ────────────
   ONE STRIP, THREE STATES, ONE ELEMENT. `.is-blocked`, `.is-ready` and `.is-frozen` change the
   colour of the same div rather than swapping one card for another, which is what "the same element
   changed, not a different element appearing" means in CSS terms. A reader who has learned where the
   gate lives has learned it once.

   THE STRIP NOW CARRIES THE FILTER PILLS AND THE FINISH LINK (frame D). Before W1 the eight KPI tiles
   were the loudest thing on the page and the pills sat under them inside the grid's own header, so the
   "what is blocking me" sentence and the "show me only what needs me" press were two screens apart.
   Story on the left, pills on the right, and at a narrow width the pills take the next line intact.

   The left border and not a full amber fill: the strip sits directly under a heading and above the
   money, and a filled band there competes with both. A 3px edge in the state colour reads at a glance
   and still lets the sentence be ordinary text. */
.est-gate[b-h5mwmolj4w] {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem 1rem;
    align-items: center;
    padding: .6rem .9rem;
    margin-bottom: .9rem;
    border-radius: 0 6px 6px 0;
    background: var(--ft-surface-2);
    font-size: .88rem;
    line-height: 1.5;
}

.est-gate.is-blocked[b-h5mwmolj4w] { border-left: 3px solid var(--ft-amber, #f59e0b); }
.est-gate.is-ready[b-h5mwmolj4w]   { border-left: 3px solid var(--ft-green-text); }
.est-gate.is-frozen[b-h5mwmolj4w]  { border-left: 3px solid var(--ft-border-strong); }

/* The sentence and its jumps: one flex run that wraps as prose, taking whatever the pills leave. */
.est-gate-story[b-h5mwmolj4w] {
    flex: 1 1 22rem;
    min-width: 0;
    display: flex;
    flex-wrap: wrap;
    gap: .35rem .9rem;
    align-items: baseline;
}

.est-gate-msg[b-h5mwmolj4w] {
    font-weight: 600;
    color: var(--ft-navy);
}

.est-gate.is-blocked .est-gate-msg[b-h5mwmolj4w] { color: var(--ft-amber-text, #b45309); }
.est-gate.is-ready   .est-gate-msg[b-h5mwmolj4w] { color: var(--ft-green-text); }
.est-gate.is-frozen  .est-gate-msg[b-h5mwmolj4w] { color: var(--ft-text-muted); font-weight: 500; }

/* The jumps sit on the same baseline as the sentence, so the strip reads as one line of prose with
   its destinations inline rather than as a sentence with a button bar under it. */
.est-gate-jumps[b-h5mwmolj4w] {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
}

/* A BUTTON that looks like a link, and both halves are deliberate. It must be a button because it
   moves the rail and DOM focus, which no href can do; it must look like a link because "→ A3.1 needs
   a rate" is a destination and a filled button there would compete with Submit for the eye — and
   Submit is the one primary action this page is allowed (P5). */
.est-gate-jump[b-h5mwmolj4w] {
    font: inherit;
    font-size: .85rem;
    font-weight: 600;
    padding: 0;
    background: none;
    border: none;
    color: var(--ft-primary);
    cursor: pointer;
    text-decoration: underline;
    text-underline-offset: 2px;
}

.est-gate-jump[b-h5mwmolj4w]::before { content: "\2192\00a0"; }

.est-gate-jump:hover[b-h5mwmolj4w] { text-decoration-thickness: 2px; }

/* ── the pills: All lines · Needs you (n) · Workings (n) · Finish ──────────────────────────────
   THREE VISUAL STATES AND THEY MEAN DIFFERENT THINGS. `is-active` is the view the grid is showing
   (navy, like every other "you are here" on this product). `is-cta` is the gate's own amber and is drawn
   on Needs-you only while the bid is blocked on a rate and the estimator is NOT already looking at that
   view — Mark's decision: All lines stays the default, and the next action is one press away rather
   than the landing view. The two are told apart by hue AND by which pill carries aria-current, so the
   distinction survives a monochrome screen. */
.est-gate-pills[b-h5mwmolj4w] {
    display: flex;
    flex-wrap: wrap;
    gap: .35rem;
    margin-left: auto;
    align-items: center;
}

.est-pill[b-h5mwmolj4w] {
    display: inline-flex;
    align-items: center;
    font: inherit;
    font-size: .8rem;
    font-weight: 600;
    line-height: 1.3;
    padding: .3rem .8rem;
    border-radius: 999px;
    border: 1px solid var(--ft-border-strong);
    background: var(--ft-surface);
    color: var(--ft-text);
    text-decoration: none;
    cursor: pointer;
    white-space: nowrap;
}

.est-pill:hover[b-h5mwmolj4w] { border-color: var(--ft-primary); color: var(--ft-primary); }

.est-pill.is-active[b-h5mwmolj4w] {
    background: var(--ft-navy);
    border-color: var(--ft-navy);
    color: var(--ft-on-navy, #fff);
}

.est-pill.is-active:hover[b-h5mwmolj4w] { color: var(--ft-on-navy, #fff); }

.est-pill.is-cta[b-h5mwmolj4w] {
    background: var(--ft-amber-text, #b45309);
    border-color: var(--ft-amber-text, #b45309);
    color: var(--ft-on-navy, #fff);
}

.est-pill.is-cta:hover[b-h5mwmolj4w] { color: var(--ft-on-navy, #fff); filter: brightness(1.08); }

/* Workings is a TOGGLE, not a view, so its pressed state is the outline going navy rather than the
   fill — a pressed toggle that looked exactly like the active filter would say two views were showing. */
.est-pill[aria-pressed="true"][b-h5mwmolj4w] {
    border-color: var(--ft-navy);
    color: var(--ft-navy);
    box-shadow: inset 0 0 0 1px var(--ft-navy);
}

/* AB#1810 — THE CALL TO ACTION TAKES THE STRIP'S COLOUR, and that is the whole of the rule.
   `is-cta` above is amber because until now the only pill that could carry it was Needs-you on a
   BLOCKED bid. The dominant action exists in every draft state now, and an amber "Finish" on a strip
   whose left border has just gone green would be the one element on the page contradicting the state
   the other four say. So the fill follows `.est-gate.is-ready`; the amber above stays the default and
   still covers every blocked state. Keyed on the strip's state class rather than on which pill it
   lands on, so it is right for whichever control is dominant. */
.est-gate.is-ready .est-pill.is-cta[b-h5mwmolj4w] {
    background: var(--ft-green-text);
    border-color: var(--ft-green-text);
}

/* ── the headline numbers, demoted to support (AB#1773 W1) ─────────────────────────────────────
   EIGHT tiles: TOTAL, ALTERNATES, GRAND, COST, MARGIN, PRICED, UNPRICED, BUILT UP — the same eight
   AB#1648 finished, and now ONE QUIET ROW under the strip instead of the loudest card on the page.
   Frame D's callout is "single progress strip — not three decorative counts": the numbers are still
   here because an estimator glances at the base bid constantly, but they are set small, in a flex run
   with no card chrome, so the strip above them is the thing the eye lands on. DURATION is still absent
   and still not buildable: nothing models crew size or programme.

   Flex and not a grid, so a tile is exactly as wide as its number and "$1,234,567" never gets crushed
   into a 9rem track; the run wraps at a narrow width. */
.est-kpis-row[b-h5mwmolj4w] {
    padding: 0 .25rem;
    margin-bottom: 1rem;
}

.est-kpis[b-h5mwmolj4w] {
    display: flex;
    flex-wrap: wrap;
    gap: .35rem 1.6rem;
    align-items: baseline;
}

.est-kpi[b-h5mwmolj4w] {
    display: flex;
    flex-direction: column;
    gap: 1px;
    min-width: 0;
}

.est-kpi-label[b-h5mwmolj4w] {
    font-size: .62rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .07em;
    color: var(--ft-text-muted);
}

.est-kpi-value[b-h5mwmolj4w] {
    font-size: .98rem;
    font-weight: 650;
    letter-spacing: -.01em;
    color: var(--ft-navy);
    font-variant-numeric: tabular-nums;
}

/* A count that is zero is not news and must not read as an alarm; a count that is not zero is the
   number that decides whether the bid can go out at all. Same tile, two states. */
.est-kpi-value.is-warning[b-h5mwmolj4w] { color: var(--ft-amber-text, #b45309); }
.est-kpi-value.is-quiet[b-h5mwmolj4w]   { color: var(--ft-text-muted); }

/* AB#1648 — the COST and MARGIN tiles when there is nothing to show. "Not measured" is a SENTENCE,
   not a figure, and must not be set like a value. */
.est-kpi-value.is-absent[b-h5mwmolj4w] {
    font-size: .82rem;
    font-weight: 500;
    letter-spacing: 0;
    color: var(--ft-text-muted);
}

/* The three caveats — what the totals exclude, what the margin left out, what is still open — used to
   be three sentences on their own row under the tiles. They are ONE muted line now, wrapped as prose;
   each still carries its testid and its own colour, so the amber ones are amber and the quiet ones quiet. */
.est-kpis-caveat[b-h5mwmolj4w] {
    display: flex;
    flex-wrap: wrap;
    gap: .15rem .8rem;
    margin-top: .3rem;
    font-size: .78rem;
    line-height: 1.45;
    color: var(--ft-text-muted);
}

/* ── two columns ───────────────────────────────────────────────────────────────────────────────
   minmax(0, 1fr) and not 1fr. A grid track defaults to min-content, and the bid table's widest
   description would then push the whole column past the viewport and take the sticky rail off the
   right-hand edge of the screen. This is the single line that makes the split hold. */
.est-split[b-h5mwmolj4w] {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 22rem;
    gap: 1rem;
    align-items: start;
}

.est-main[b-h5mwmolj4w] {
    min-width: 0;
}

/* THE RAIL GIVES BACK, AT THE WIDTH WHERE IT COSTS MOST (AB#1802). Releasing the 720 px floor below
   stops the grid scrolling sideways, and on its own it would have bought that by taking 103 px off
   the description — 173 px at 1280, narrower than the 276 px the clipped layout had. That is a
   readability regression traded for a clipping fix, which is not a trade worth making.

   MEASURED at 1280x900: sidebar 240, page padding 75, gap 15, rail 330 — the grid gets 618 of 1280.
   The rail is the one term in that sum this page owns. At 19rem it is 285 px, the grid is 663, and
   the description column goes to 218 px (35% of the grid) with everything on screen at once. Above
   1400 nothing changes and the rail stays the 22rem frame D draws.

   Not the column widths, deliberately. Each of the five fixed widths was measured for a reason that
   is written beside it on the <th> — 4.7rem so Spanish "PARTIDA" does not break mid-word, 7.1rem so
   Atlas's five-figure lump sums do not run into the amount beside them — and shaving them at 1280
   would re-open exactly what AB#1773 W1 measured shut. */
@media (max-width: 1400px) {
    .est-split[b-h5mwmolj4w] {
        grid-template-columns: minmax(0, 1fr) 19rem;
    }
}

/* ── the grid: the description gets the space (AB#1773 W1) ─────────────────────────────────────
   MEASURED, not guessed, in a browser at 1440 with the rail beside the grid. Before W1 the seven
   narrow columns were fixed widths on the <th> but the table was auto-laid-out, so each column grew to
   its HEADING's nowrap min-content — and in Spanish "PRECIO UNITARIO" and "UNIDAD" are wide headings,
   which is why the description column on stage was a five-line ribbon while the English screenshots
   looked fine. The numbers before and after are on AB#1773.

   So: `table-layout: fixed` makes the <th> widths authoritative, headings are ALLOWED TO WRAP inside
   their column, and the description — the only column with no width of its own — takes everything the
   other seven leave. The same rule as the rail title: the client's wording is theirs and is never
   shortened, it is clamped to two lines with the whole text in the title.

   SCOPED TO THE GRID, and the selector now says so (AB#1808). It read `.est-main .ft-table` and this
   comment claimed it changed "THIS page's grid and no other `.ft-table` in the product" — but there are
   TWO `.ft-table`s inside `.est-main`, this grid and the revision-diff table a thousand lines below, and
   the rule was silently authoritative over both. On a table whose six `<th>`s ask for 49.5rem inside a
   592 px scrollport, `table-layout: fixed` gives each column what it asked for and leaves the only
   column without a width of its own — the DESCRIPTION — at literally zero pixels, with 151 px of forced
   sideways scroll at 1280 and 36 px at 1440. Measured, in all three locales, before this line changed.

   A comment asserting a scope the selector does not have is the same failure as a guard that scans
   nothing: it reads as a decision that was made and was not. `.est-grid-scroll` is the grid's own
   viewport and is the scope this rule always meant. */
.est-main .est-grid-scroll .ft-table[b-h5mwmolj4w] {
    table-layout: fixed;
    width: 100%;
}

/* The padding, by contrast, STAYS broad on purpose — it is right for both tables and narrowing it with
   the rule above would have cost the diff table 240 px of cell padding across six columns at the exact
   width where it has none to spare. Same selector shape, opposite decision, because the question is
   what each rule is true OF and not where it happens to sit in this file. */
.est-main .ft-table th[b-h5mwmolj4w] {
    white-space: normal;
    overflow-wrap: anywhere;
    letter-spacing: .04em;
    line-height: 1.25;
    vertical-align: bottom;
}

/* The whole of the rest of the difference is padding. app.css gives every cell 1.25rem each side,
   which is right for a full-width table and is 20 rem of horizontal padding across eight columns here. */
.est-main .ft-table th[b-h5mwmolj4w],
.est-main .ft-table td[b-h5mwmolj4w] {
    padding-left: .45rem;
    padding-right: .45rem;
}

.est-main .ft-table th:first-child[b-h5mwmolj4w],
.est-main .ft-table td:first-child[b-h5mwmolj4w] {
    padding-left: .9rem;
}

.est-main .ft-table th:last-child[b-h5mwmolj4w],
.est-main .ft-table td:last-child[b-h5mwmolj4w] {
    padding-right: .9rem;
}

/* A fixed layout does not let a cell grow for a long chip, so the chip wraps inside its column instead
   of painting over the neighbour. "Introducido a mano" is two short lines in Spanish, and still a chip. */
.est-main .ft-table .est-chip[b-h5mwmolj4w] {
    white-space: normal;
    text-align: center;
}

/* The client's item code, with their sheet row under it in small type (AB#1773 W1). The row used to be a
   column of its own; it is the same number and the same link, one line down, so the description gets
   the 50 px it took. */
.est-code[b-h5mwmolj4w] {
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    color: var(--ft-navy);
    vertical-align: top;
}

.est-code-row[b-h5mwmolj4w] {
    margin-top: .15rem;
    font-size: .72rem;
    font-weight: 500;
    color: var(--ft-text-faint);
}

/* The quantity with its unit beside it — "240 m²" — as frame D draws it, instead of a unit column.

   AB#2184 — THE CELL MAY WRAP; ITS PIECES MAY NOT. The column is a fixed 4.6rem (about 55 px of content
   under the grid's padding) and this rule used to be `nowrap` for the whole cell, so anything wider simply
   painted over the RATE cell beside it: "1 Lump Sum" by 37 px and the "No quantity" control by 37-88 px,
   on 15 of 27 lines of a loaded in-flight bid and 23 of 58 on the engineer's issued form, at 1280, 1440
   and 1920 alike (a fixed column is not a narrow-window bug). Measured in a browser; bUnit loads no
   stylesheet. Now the unit is one unbreakable piece that sits beside the number when it fits and under it
   when it does not, so "240 m²" still reads on one line; only a unit wider than the whole column
   ("Lump Sum", 63 px at .78rem) then breaks between its own words. The "No quantity" control's own sizing is on its
   inline style in the markup, beside EditableCellStyle, because an inline min-width beats any rule here. */
.est-qty[b-h5mwmolj4w] {
    white-space: normal;
}

.est-unit[b-h5mwmolj4w] {
    display: inline-block;
    max-width: 100%;
    white-space: normal;
    margin-left: .3rem;
    font-size: .78rem;
    color: var(--ft-text-muted);
}

/* The rate cell on a line that has none (AB#1812). The same amber the quantity cell's "No quantity"
   already uses, because they are the same invitation in the same row and two colours for one state
   would say they were different kinds of gap.

   SMALLER THAN THE MONEY BESIDE IT and not bold: the column is a column of figures, right-aligned and
   tabular, and a full-weight phrase in it would break the number column an estimator scans down. The
   affordance is carried by the cell's own inline editable style (see EditableCellStyle) — this rule is
   colour and size only, which is the split this file's header sets out. */
.est-rate-empty[b-h5mwmolj4w] {
    font-size: .82rem;
    font-weight: 600;
    color: var(--ft-amber-text, #b45309);
    white-space: nowrap;
}

/* ── the grid scrolls; the page does not (AB#1729) ─────────────────────────────────────────────
   THIS IS THE RULE THAT FIXES THE PAGE LENGTH, and it is here because it was MEASURED rather than
   assumed. In a browser at 1440, on estimates of 33, 250 and 1,000 bid lines:

       lines   page height   grid markup   DOM elements   rate cell open
          33      6,215 px         86 KB            970            5 ms
         250     40,919 px        632 KB          4,160           23 ms
       1,000    171,629 px        2.5 MB         15,187           95 ms

   So the change the numbers justify is a BOUNDED VIEWPORT, not virtualisation. Virtualisation shortens
   the markup and NOT the page — a virtualised list keeps its scroll height in spacers — so it would
   have left the one measurement that is out of budget exactly where it was, at the price of breaking
   the roving-tabindex keyboard grid, which needs the cell it is moving to to exist.

   `min()` and not a bare `calc()`: on a short viewport the subtraction can go negative, and a
   max-height below the min-height would collapse the grid to nothing on exactly the laptop that can
   least afford it. The floor is 18rem, about four bid lines, which is a grid you can still work in.

   `--ft-surface` for the sticky heading and not `.ft-table th`'s own background: that one is
   `rgba(255,255,255,.015)`, which is translucent, and a translucent frozen header shows the rows
   sliding underneath it. --ft-surface is the card's own opaque background in both themes. */
.est-main .est-grid-scroll[b-h5mwmolj4w] {
    max-height: min(72vh, calc(100vh - 18rem));
    min-height: 18rem;
    overflow-y: auto;
}

/* ── AND THE GRID DOES NOT SCROLL SIDEWAYS EITHER (AB#1802) ────────────────────────────────────
   THE WHOLE OF THAT TICKET IS THIS ONE INHERITED RULE. `.ft-table-scroll .ft-table` in app.css
   sets `min-width: 720px`, which is right for the generic full-width tables it was written for and
   wrong for a table sharing its row with a 22rem rail. MEASURED at 1280x900 with the rail open,
   before this line existed:

       scrollport   618 px        table   720 px        overflow   102 px

   and at 1440, 778 px against 778 — no overflow, which is exactly why Steve's 1440 pass looked
   clean and his 1280 pass did not. Everything on AB#1802 is downstream of that 102 px: a
   description can only clip mid-word under the left edge once `scrollLeft` can be greater than
   zero, and a frozen heading can only drift off its column once the column can move under it.

   `table-layout: fixed` with `width: 100%` above already makes the table exactly as wide as its
   scrollport. Releasing the floor is therefore not "letting it shrink" — it is letting the layout
   algorithm that is already in force actually decide, at which point scrollLeft is pinned at 0 and
   both symptoms are unreachable rather than mitigated. Scoped to THIS grid: the revision-diff table
   further down the page is an ordinary `.ft-table-scroll` and keeps app.css's floor.

   This is the direction Steve named on the ticket ("avoid forcing H-scroll at 1280 with rail open")
   in preference to freezing leading columns with a real sticky left, and it is the one that cannot
   rot: a sticky-left column has to be kept in step with every future column change, and a table
   that never scrolls sideways has nothing to keep in step. */
.est-main .est-grid-scroll .ft-table[b-h5mwmolj4w] {
    min-width: 0;
}

/* ── AND NEITHER DOES THE REVISION-DIFF TABLE (AB#1808) ────────────────────────────────────────
   THE CARD SAID THIS TABLE INHERITS THE 720 px FLOOR AND THAT RELEASING IT IS THE FIX. Measured,
   that is not what was wrong, and releasing the floor alone would have closed the ticket on a table
   still scrolling 151 px — a floor of 720 cannot be what makes a table 743 wide.

       1280   scrollport 592 px   table 743 px   151 px of forced sideways scroll
       1440   scrollport 707 px   table 743 px    36 px

   Identical in EN, DE and ES, because the width came from the stylesheet and not from the strings.
   The cause was `table-layout: fixed` reaching this table from the rule written for the line grid,
   which is fixed at its source above. Under fixed layout the five explicit `<th>` widths (7 + 4.5 +
   10 + 10 + 18 = 49.5rem) took what they asked for and the DESCRIPTION — the one column with no
   width of its own, and the one naming the line that moved — was laid out at ZERO pixels.

   With the layout back to `auto` the widths become preferences the browser may compress, which is
   the behaviour those numbers were written for: 18rem is what "What moved" WANTS, not a floor it
   needs. The 720 px floor still has to go, because 720 in a 592 px scrollport is 128 px of scroll on
   its own — released HERE, scoped to this table, never in app.css, where the floor is shared with
   full-width tables on other screens that genuinely want it.

   The two halves are both necessary and neither is sufficient: the layout mode is what zeroed the
   description, the floor is what would still have scrolled it. */
.est-main .est-secondary-body .ft-table-scroll .ft-table[b-h5mwmolj4w] {
    min-width: 0;
}

.est-main .est-grid-scroll thead th[b-h5mwmolj4w] {
    position: sticky;
    top: 0;
    z-index: 2;
    background: var(--ft-surface);
    /* A COLLAPSED border does not travel with a sticky cell — the table owns it, the cell only draws it,
       and a stuck cell leaves it behind at the top of the table. An inset shadow is painted by the cell
       itself, so it stays with it. */
    box-shadow: inset 0 -1px 0 var(--ft-border);
}

/* Below the shell's breakpoint the rail is already unpinned and the whole page is one column. A grid
   that still scrolled inside itself there would put two scrollbars in a phone's width, so the viewport
   is released and the page scrolls as it always did. */
@media (max-width: 1100px) {
    .est-main .est-grid-scroll[b-h5mwmolj4w] {
        max-height: none;
        min-height: 0;
        overflow-y: visible;
    }
}

/* The client's own description, allowed to wrap mid-token. One real line —
   "Mobilization/Demobilization/General Conditions" — is a single unbreakable token to a browser and on
   its own set a 273 px minimum under this column. Their wording is theirs and is never shortened. */
.est-desc[b-h5mwmolj4w] {
    overflow-wrap: anywhere;
}

/* TWO LINES AND A TITLE — the rail has clamped its own title this way since AB#1752, and the grid
   now does the same (frame D: "descriptions clamp 2 lines + title"). The whole text is on the cell's
   title attribute, so a hover reads it and nothing is lost; a screen reader reads the full text
   because clamping is paint, not content. The note under it clamps the same way: the seed's unpriced
   notes are sentences, and four lines of note under a two-line description would be the old page. */
.est-desc-text[b-h5mwmolj4w],
.est-desc-note[b-h5mwmolj4w] {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.est-desc-text[b-h5mwmolj4w] {
    line-height: 1.45;
}

.est-desc-note[b-h5mwmolj4w] {
    margin-top: .2rem;
    font-size: .78rem;
    line-height: 1.4;
    color: var(--ft-text-faint);
}

/* ── the price-book suggestion, as a band under its line (AB#1804) ─────────────────────────────
   MEASURED on seeded 25-189 (AB#1796: 25 proposals across 58 unpriced lines) before this changed,
   at BOTH 1280 and 1440, in EN/DE/ES:

       proposal block    89 px wide
       block height      515 px (EN) · 565 px (DE, ES)
       cited sentence    8 lines (EN) · 10 lines (DE) · 9 lines (ES)

   The width is identical at both viewport widths, because the block was inside the AMOUNT cell and
   that column is a fixed 6.8rem at every width — this was never a narrow-window bug. A currency
   column is sized for "$38,500.00"; the thing being drawn in it was a graded, cited sentence.

   So the block is a SIBLING ROW of the same grid now, which is the shape AB#1650 already chose for
   the workings, for the same reason: a thing that does not fit a cell does not get to fight its
   neighbours for one. It keeps the line's amber tint and the line above it drops its rule
   (`.est-line-proposed`), so the pair reads as one line and not as two.

   ONE FLOWING PARAGRAPH, not three stacked divs. The suggestion, the grade badge, the evidence and
   the reason are one sentence in the ticket's own quotation of it, and setting them as three blocks
   in a 22rem-rail layout is what made the German render ten lines deep. The button sits at the end
   of the run and drops under it when there is no room, which is the same flex-wrap the gate strip
   and `.est-diff-more` use. */
.est-line-proposed > td[b-h5mwmolj4w] { border-bottom: none; }

/* BOTH cells, and the gutter is not decoration. `.ft-table td` pads .9rem top and bottom, so an empty
   first cell left at the default would set the row's height on its own and undo half the point of the
   move. The gutter is what starts the prose under the DESCRIPTION rather than under the item code. */
.est-proposal-gutter[b-h5mwmolj4w],
.est-proposal-cell[b-h5mwmolj4w] {
    padding-top: 0;
    padding-bottom: .6rem;
}

.est-proposal[b-h5mwmolj4w] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .35rem .75rem;
    font-size: .8rem;
    font-weight: 400;
    line-height: 1.5;
    text-align: left;
    color: var(--ft-text-muted);
}

/* 18rem, so the run wraps the BUTTON under the prose rather than breaking the prose into a ribbon
   beside it — the failure this ticket is about, one level up. */
.est-proposal-prose[b-h5mwmolj4w] {
    flex: 1 1 18rem;
    min-width: 0;
}

.est-proposal-lede[b-h5mwmolj4w] { color: var(--ft-navy); }

.est-proposal-evidence[b-h5mwmolj4w] {
    margin-left: .3rem;
    color: var(--ft-amber-text, #92400e);
}

.est-proposal-because[b-h5mwmolj4w] { margin-left: .3rem; }

.est-proposal-error[b-h5mwmolj4w] {
    margin-top: .2rem;
    color: var(--ft-danger, #b91c1c);
}

.est-proposal-use[b-h5mwmolj4w] {
    flex: 0 0 auto;
    font-size: .78rem;
    padding: .2rem .6rem;
}

/* ── the disclosures below the grid: history, then documents (AB#1753, AB#1773 W1) ─────────────
   The documents card used to sit between the progress strip and the first bid row, so the path from
   "what is stopping me" to "the work" ran through a list of files. It is one disclosure below the grid
   now, shut unless something in it needs saying. The revision history joined it in W1: it is about the
   BID (what moved since the last revision, which rates can be carried), not about the selected line,
   so it left the rail and sits here, open when there is something to act on.

   A NATIVE <details>, not a button and a boolean. The disclosure triangle, the keyboard behaviour and
   the "expand this to search inside it" hook browsers give find-in-page all come free.

   The summary is a GRID rather than a flex row: the guard sentence and the fallback flag must be able
   to wrap onto their own lines in German without pushing the title out of the panel. */
.est-secondary[b-h5mwmolj4w] {
    border: 1px solid var(--ft-border);
    border-radius: 8px;
    background: var(--ft-surface);
    margin-bottom: 1rem;
}

/* THE SUMMARY KEEPS ITS DEFAULT `display: list-item`, and the grid goes on a div INSIDE it. That is not
   a style preference: `list-item` is what draws the disclosure triangle, and `display: grid` here would
   silently remove it in Chrome and Safari — leaving a heading with no sign it can be opened. */
.est-secondary-summary[b-h5mwmolj4w] {
    padding: .8rem 1rem;
    cursor: pointer;
}

.est-secondary-head[b-h5mwmolj4w] {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: .15rem .75rem;
}

.est-secondary-title[b-h5mwmolj4w] {
    font-size: .98rem;
    font-weight: 650;
    color: var(--ft-navy);
}

.est-secondary-meta[b-h5mwmolj4w] {
    font-size: .85rem;
    color: var(--ft-text-muted);
    align-self: baseline;
}

/* "There is no original bid form on file for this estimate", and the four other fallback sentences.
   Amber and not red: it changes what an estimator may trust, which is not the same as the export pair's
   "send this and you have published our margins". */
.est-secondary-flag[b-h5mwmolj4w] {
    grid-column: 1 / -1;
    margin-top: .2rem;
    font-size: .82rem;
    color: var(--ft-amber-text, #b45309);
}

/* The cards inside were built to sit full-width in one column and already carry their own margins, so
   the body only has to stop them touching the disclosure's own border. */
.est-secondary-body[b-h5mwmolj4w] {
    padding: 0 1rem .25rem;
    border-top: 1px solid var(--ft-border-soft);
}

/* ── the context rail ──────────────────────────────────────────────────────────────────────────
   Sticky under the 52px topbar, which is itself sticky at top:0. The rail is what makes the
   re-parenting worth doing: an explanation that scrolls away from the row it explains is a
   footnote. Since W1 it is the INSPECTOR FOR THE SELECTED LINE and nothing else — Reason and Adjust —
   which is Mark's decision 2 on AB#1773 and frame D's third callout. */
.est-rail[b-h5mwmolj4w] {
    position: sticky;
    top: calc(52px + 1rem);
    max-height: calc(100vh - 52px - 2rem);
    display: flex;
    flex-direction: column;
    min-height: 0;
    margin-bottom: 1rem;
}

/* ── what the rail is about (AB#1752) ──────────────────────────────────────────────────────────
   flex-shrink: 0, like the tab strip under it. The rail is a flex column with a max-height, and a
   header that is allowed to shrink would be squeezed to nothing by a long panel instead of the pane
   scrolling — which is what `.est-rail-body` is for. */
.est-rail-head[b-h5mwmolj4w] {
    padding: .8rem 1rem .6rem;
    border-bottom: 1px solid var(--ft-border-soft);
    flex-shrink: 0;
}

.est-rail-eyebrow[b-h5mwmolj4w] {
    font-size: .68rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .08em;
    color: var(--ft-text-muted);
}

/* The client's own description, allowed to wrap mid-token for the reason `.est-desc` records, and
   capped at two lines so a long description cannot push the tabs below the fold on a laptop. */
.est-rail-title[b-h5mwmolj4w] {
    margin-top: 2px;
    font-size: .9rem;
    font-weight: 600;
    line-height: 1.35;
    color: var(--ft-navy);
    overflow-wrap: anywhere;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/* The panel that explains the problem also offers the fix. Full width because it is the one action in
   this pane, and a button that has to be aimed at is a button that reads as optional. */
.est-rail-cta[b-h5mwmolj4w] {
    display: block;
    width: 100%;
    margin-top: .9rem;
    font-size: .85rem;
}

/* EQUAL COLUMNS, HOWEVER MANY TABS. It was `repeat(4, …)` when the rail had four; W1 takes it to
   two (Reason · Adjust), and a fixed count would leave two empty tracks. Labels wrap inside their
   column rather than pushing a tab out of sight — but nothing here carries a COUNT in a tab any more
   (lane 0's observation on AB#1773: "Unknowns · 3" wrapped onto two lines in English at 22rem). */
.est-rail-tabs[b-h5mwmolj4w] {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: minmax(0, 1fr);
    border-bottom: 1px solid var(--ft-border-soft);
    flex-shrink: 0;
}

.est-tab[b-h5mwmolj4w] {
    padding: .5rem .3rem;
    font: inherit;
    font-size: .78rem;
    font-weight: 600;
    line-height: 1.25;
    text-align: center;
    color: var(--ft-text-muted);
    background: none;
    border: none;
    border-bottom: 2px solid transparent;
    cursor: pointer;
    min-width: 0;
    overflow-wrap: anywhere;
}

.est-tab:hover[b-h5mwmolj4w] { color: var(--ft-text); }

.est-tab.is-active[b-h5mwmolj4w] {
    color: var(--ft-primary);
    border-bottom-color: var(--ft-primary);
}

/* The panes scroll INSIDE the rail, so a long explanation cannot push the tabs off screen. */
.est-rail-body[b-h5mwmolj4w] {
    overflow-y: auto;
    overflow-x: hidden;
    min-height: 0;
    padding: .9rem 1rem;
}

/* Every pane is in the DOM and the inactive ones carry `hidden`. That is a deliberate choice over
   rendering only the active one: `hidden` is honoured by assistive technology, the browser keeps
   scroll position per pane, and an editor draft survives a glance at the Reason pane.

   THIS RULE IS LOAD-BEARING AND LOOKS REDUNDANT. `display: block` below is an author style and
   `[hidden] { display: none }` is a USER-AGENT style, so without the second selector the author
   rule wins and the panes render on top of each other. It is the exact shape of the swallowed
   rule this codebase has been bitten by — invisible to any test that only reads the DOM, because
   the DOM is correct and only the painting is wrong. `EstimateWorkspaceLayoutTests` reads this file
   and fails if the selector goes. */
.est-pane[b-h5mwmolj4w] { display: block; }
.est-pane[hidden][b-h5mwmolj4w] { display: none; }

.est-pane-empty[b-h5mwmolj4w] {
    color: var(--ft-text-muted);
    font-size: .85rem;
    line-height: 1.55;
}

/* The cards that were built to sit full-width in one column are now inside a 22rem rail, so their
   own outer chrome would draw a card inside a card. ::deep because these are other components'
   elements — this page owns where they sit, not what they say. */
.est-pane[b-h5mwmolj4w]  .ft-card {
    box-shadow: none;
    border: none;
    background: none;
    border-radius: 0;
    margin-bottom: 0;
}

/* ── the Adjust pane: the rate editor, docked (AB#1773 W1, frame E) ────────────────────────────
   The editor used to be a full-width row inserted UNDER the line, which shoved the rest of the section
   down the screen every time a rate was opened — frame E's "problem today". Docked here the grid
   rhythm stays put, the rate box is beside the row it prices, and after a save the pane names the next
   line that needs one. Fields stack: the rail is 22rem and three inputs in a row would be three
   inputs nobody can read. */
.est-adjust[b-h5mwmolj4w] {
    display: flex;
    flex-direction: column;
    gap: .55rem;
}

.est-adjust-title[b-h5mwmolj4w] {
    font-weight: 650;
    color: var(--ft-navy);
    font-size: .92rem;
}

.est-adjust-hint[b-h5mwmolj4w] {
    color: var(--ft-text-muted);
    font-size: .8rem;
    line-height: 1.5;
}

.est-adjust-field[b-h5mwmolj4w] {
    display: block;
    font-size: .76rem;
    color: var(--ft-text-muted);
}

.est-adjust-input[b-h5mwmolj4w] {
    display: block;
    width: 100%;
    margin-top: .2rem;
    padding: .38rem .5rem;
    border: 1px solid var(--ft-border-strong);
    border-radius: 6px;
    font: inherit;
    font-size: .88rem;
    font-variant-numeric: tabular-nums;
    background: var(--ft-surface);
    color: var(--ft-text);
}

.est-adjust-actions[b-h5mwmolj4w] {
    display: flex;
    gap: .5rem;
    align-items: center;
    margin-top: .2rem;
}

/* What the Adjust pane says about the selected line before the editor is open: the rate as it stands,
   or the amber word for no rate at all — and then the one button. */
.est-adjust-current[b-h5mwmolj4w] {
    font-size: .85rem;
    color: var(--ft-text-muted);
    line-height: 1.5;
}

.est-adjust-current strong[b-h5mwmolj4w] {
    color: var(--ft-navy);
    font-variant-numeric: tabular-nums;
}

/* "A3.1 saved. Next: A3.2 still needs a rate." — the sentence that makes the advance visible. A
   selection that moved without a word would read as the rail changing its mind. */
.est-adjust-outcome[b-h5mwmolj4w] {
    margin: 0 0 .7rem;
    padding: .55rem .75rem;
    border-left: 3px solid var(--ft-green-text);
    background: var(--ft-green-bg);
    color: var(--ft-green-text);
    border-radius: 0 6px 6px 0;
    font-size: .83rem;
    line-height: 1.5;
}

/* The way from the rail to the Questions step (AB#1773 W1). A footer, not a tab: the questions are about
   the bid and live on their own page; the rail is about the selected line. It carries the gate's own
   count in the gate's own words, so nothing here can disagree with the strip. */
.est-rail-foot[b-h5mwmolj4w] {
    flex-shrink: 0;
    padding: .6rem 1rem .8rem;
    border-top: 1px solid var(--ft-border-soft);
}

.est-rail-link[b-h5mwmolj4w] {
    font-size: .85rem;
    font-weight: 600;
    color: var(--ft-primary);
    text-decoration: underline;
    text-underline-offset: 2px;
}

.est-rail-link[b-h5mwmolj4w]::after { content: "\00a0\2192"; }

/* ── one column, and the rail underneath ───────────────────────────────────────────────────────
   1100px is the shell's own breakpoint — the fixed sidebar becomes a drawer there — so the split
   collapses on the same line rather than inventing a second one. Below it the rail stops being
   sticky: a sticky panel in a single column would sit over the table it is meant to explain. */
@media (max-width: 1100px) {
    .est-split[b-h5mwmolj4w] {
        grid-template-columns: minmax(0, 1fr);
    }

    .est-rail[b-h5mwmolj4w] {
        position: static;
        max-height: none;
    }

    .est-rail-body[b-h5mwmolj4w] {
        overflow-y: visible;
    }
}

/* ── the source chip, coloured by mechanism ────────────────────────────────────────────────────
   The point of the colour is scanning: on a 33-line bid, "which of these rates are evidenced and
   which are somebody's opinion" is answered at a glance instead of by reading 33 rows of grey.
   `EstimateLineProvenance` already carries the mechanism on every line, so this is markup and
   colour against a value we have stored since AB#1614.

   Colour is never the ONLY carrier: every chip keeps its words, and the two amber states are told
   apart by fill rather than by hue, so this survives a monochrome screen and colour blindness. */
.est-chip[b-h5mwmolj4w] {
    display: inline-block;
    padding: .15rem .5rem;
    border-radius: 999px;
    font: inherit;
    font-size: .75rem;
    font-weight: 600;
    line-height: 1.35;
    white-space: nowrap;
    background: var(--ft-surface-2);
    color: var(--ft-text-muted);
    border: 1px solid transparent;
    cursor: pointer;
}

.est-chip:hover[b-h5mwmolj4w] { filter: brightness(.97); }

.est-chip--sm[b-h5mwmolj4w] {
    font-size: .7rem;
    padding: .1rem .4rem;
    font-weight: 500;
    cursor: default;
}

/* Price book — the strongest provenance we hold, because the customer maintains it themselves. */
.est-chip--book[b-h5mwmolj4w] {
    background: var(--ft-green-bg);
    color: var(--ft-green-text);
}

/* History — evidence rather than policy, and one step weaker than the catalogue. */
.est-chip--history[b-h5mwmolj4w] {
    background: var(--ft-blue-bg);
    color: var(--ft-blue-text);
}

/* A rule is deterministic and explainable and still encodes a DECISION rather than a measurement,
   which is why it is neither the catalogue's green nor history's blue. */
.est-chip--rule[b-h5mwmolj4w] {
    background: var(--ft-teal-bg);
    color: var(--ft-teal-text);
}

/* A person typed it, on this revision. Always wins over anything automatic. */
.est-chip--manual[b-h5mwmolj4w] {
    background: var(--ft-purple-bg);
    color: var(--ft-purple-text);
}

/* AB#2253 — read from the client's own bid form. Navy text on the surface with a SOLID border: the figure is the
   client's, unchanged, so it borrows neither the purple of a person here deciding it nor a mechanism's colour.
   Told apart from "Computed" (dashed) by the border style as well as the words. */
.est-chip--bidform[b-h5mwmolj4w] {
    background: var(--ft-surface-2);
    color: var(--ft-navy);
    border-color: var(--ft-border-strong);
}

/* AB#1641 — priced from a subcontractor's quote. Declared tokens only (an undeclared one falls back to its light hex on a
   dark card): navy on the surface like the client's own figure, with a TWO-pixel border — a named partner's price marked
   up through the org's divisor, neither typed here nor a mechanism's. Told apart by the words as well. */
.est-chip--subquote[b-h5mwmolj4w] {
    background: var(--ft-surface-2);
    color: var(--ft-navy);
    border: 2px solid var(--ft-border-strong);
}

/* Carried forward: amber OUTLINE, not amber fill, and told apart from unpriced by that alone if the
   words are ever lost. It is the one state on this grid that asks the reader to go and check
   something — the rate was decided against a form the engineer has since reissued. */
.est-chip--carried[b-h5mwmolj4w] {
    background: none;
    color: var(--ft-amber-text, #b45309);
    border-color: var(--ft-amber, #f59e0b);
}

/* No rate was produced. A first-class outcome, not a failure — and the count of these is the number
   that decides whether the bid can go out. */
.est-chip--unpriced[b-h5mwmolj4w] {
    background: var(--ft-amber-bg);
    color: var(--ft-amber-text, #b45309);
}

/* AB#1870 — computed from sub-lines. Navy on the surface, deliberately NONE of the mechanism colours: no
   mechanism produced this figure, the rows beneath it did, and a green or purple here would borrow the
   authority of a catalogue or a person. The dashed border is what says "made of other things". */
.est-chip--derived[b-h5mwmolj4w] {
    background: var(--ft-surface-2);
    color: var(--ft-navy);
    border: 1px dashed var(--ft-border-strong);
}

/* The Σ chip in the RATE column. It is the cell's tab stop and the door to the composition in the rail, so
   it is a button — but it must never read as the boxed, typeable field an editable rate cell is. */
.est-derived-chip[b-h5mwmolj4w] {
    display: inline-block;
    margin-left: .35rem;
    padding: .05rem .4rem;
    border-radius: 999px;
    border: 1px dashed var(--ft-border-strong);
    background: none;
    color: var(--ft-text-muted);
    font: inherit;
    font-size: .72rem;
    font-weight: 600;
    white-space: nowrap;
    cursor: pointer;
}

.est-derived-chip:hover[b-h5mwmolj4w] { color: var(--ft-navy); }

/* The rail's composition (design 05b). One row per sub-line: its words, its arithmetic, its Adjust. */
.est-derived-rows[b-h5mwmolj4w] {
    list-style: none;
    margin: .6rem 0 0;
    padding: 0;
    display: grid;
    gap: .45rem;
}

.est-derived-rows li[b-h5mwmolj4w] {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: .15rem .5rem;
    align-items: center;
    padding-bottom: .4rem;
    border-bottom: 1px solid var(--ft-border);
    font-size: .82rem;
}

.est-derived-desc[b-h5mwmolj4w] {
    grid-column: 1 / -1;
    color: var(--ft-navy);
    overflow-wrap: anywhere;
}

.est-derived-sum[b-h5mwmolj4w] {
    color: var(--ft-text-muted);
    font-variant-numeric: tabular-nums;
    overflow-wrap: anywhere;
}

.est-derived-adjust[b-h5mwmolj4w] {
    font-size: .75rem;
    padding: .15rem .55rem;
}

.est-derived-total[b-h5mwmolj4w] {
    display: flex;
    justify-content: space-between;
    gap: .5rem;
    margin-top: .6rem;
    font-size: .85rem;
    color: var(--ft-navy);
    font-variant-numeric: tabular-nums;
}

/* ── the way through to the full comparison (AB#1749) ──────────────────────────────────────────
   A RULE ABOVE IT, because this is the one thing in the card that leaves the card. Everything else
   between the headline and here is the comparison itself; a button dropped straight under the last
   table row reads as another control over that table.

   The sentence is BESIDE the button when there is room and UNDER it when there is not — the same
   flex-wrap the gate strip uses — so a reader never gets a button whose reason has been pushed off
   the edge. The button itself is `.ft-btn.ft-btn-outline` from app.css and is styled by nothing here. */
.est-diff-more[b-h5mwmolj4w] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .5rem .9rem;
    margin-top: 1rem;
    padding-top: .9rem;
    border-top: 1px solid var(--ft-border);
}

.est-diff-more-why[b-h5mwmolj4w] {
    flex: 1 1 18rem;
    color: var(--ft-text-muted);
    font-size: .83rem;
    line-height: 1.5;
}

/* AB#1871 — the basis quantity sits under the engineer's stated one, smaller, because his is the paperwork. */
.est-qty-basis[b-h5mwmolj4w] {
    display: block;
    font-size: .74rem;
    font-weight: 600;
    color: var(--ft-amber-text, #b45309);
}

/* AB#1801 — the "Revise this bid" panel. Why this revision exists moved to EstimateRevisionReason.razor.css (AB#2280). */
.est-revise[b-h5mwmolj4w] {
    margin-top: .75rem;
    padding: .9rem 1rem;
    max-width: 44rem;
}

.est-revise-title[b-h5mwmolj4w] {
    margin: 0 0 .4rem;
    font-size: 1rem;
    font-weight: 600;
}

.est-revise-explain[b-h5mwmolj4w] {
    margin: 0 0 .6rem;
    font-size: .88rem;
    color: var(--ft-text-muted);
}

.est-revise-problem[b-h5mwmolj4w] {
    margin-top: .6rem;
    padding: .55rem .8rem;
    border-radius: 8px;
    background: var(--ft-amber-bg);
    color: var(--ft-amber-text);
    font-size: .88rem;
    display: flex;
    flex-wrap: wrap;
    gap: .6rem;
}

.est-revise-actions[b-h5mwmolj4w] {
    display: flex;
    gap: .6rem;
    margin-top: .8rem;
}

/* AB#1805 — at cost: a person's decision, so a solid neutral chip rather than the amber of "needs a rate". */
.est-chip--atcost[b-h5mwmolj4w] {
    background: var(--ft-surface-2);
    color: var(--ft-navy);
    border: 1px solid var(--ft-border-strong);
}

/* AB#1895 — subcontracted scope, under the description. Not a provenance (it says who does the work, not where the
   rate came from), so it borrows none of the mechanism colours: navy words on the surface with a DOUBLE border for a
   person's marking, and a dotted one for a proposal nobody has accepted. Told apart by the words as well. A span, not
   a control: the line's row and the rail are where it is acted on, so it does not take the chip's pointer. */
.est-chip--sub[b-h5mwmolj4w],
.est-chip--sub-proposed[b-h5mwmolj4w] {
    display: inline-block;
    margin-top: .3rem;
    cursor: default;
    background: var(--ft-surface-2);
    color: var(--ft-navy);
}

.est-chip--sub[b-h5mwmolj4w] {
    border: 3px double var(--ft-border-strong);
}

.est-chip--sub-proposed[b-h5mwmolj4w] {
    border: 1px dotted var(--ft-border-strong);
    font-weight: 500;
}

.est-atcost[b-h5mwmolj4w] {
    margin-top: .6rem;
    font-size: .85rem;
}

.est-atcost-by[b-h5mwmolj4w] {
    margin-top: .2rem;
    color: var(--ft-text-muted);
}

.est-atcost-suggest[b-h5mwmolj4w] {
    margin-bottom: .4rem;
    color: var(--ft-text-muted);
}

/* AB#1877 — the approval chain on the workspace: the approver's read-only banner and the send-back note. */
.est-review-banner[b-h5mwmolj4w] {
    margin: .5rem 0;
    padding: .5rem .8rem;
    border-radius: 8px;
    background: var(--ft-surface-2);
    color: var(--ft-text-muted);
    font-size: .88rem;
}

.est-sent-back[b-h5mwmolj4w] {
    padding: .15rem .5rem;
    border-radius: 6px;
    background: var(--ft-amber-bg);
    color: var(--ft-amber-text);
    font-size: .85rem;
}

/* AB#2193 — a proposals-log row: one honest panel where the grid would ask for a bid form. */
.est-log-record[b-h5mwmolj4w] {
    max-width: 46rem;
    padding: 1.25rem 1.25rem .5rem;
}

.est-log-record-origin[b-h5mwmolj4w] { margin: 0 0 .6rem; }

.est-log-record-text[b-h5mwmolj4w] {
    margin: 0 0 .75rem;
    color: var(--ft-text);
    line-height: 1.5;
}

.est-log-record-actions[b-h5mwmolj4w] { margin: 0 0 .9rem; }

/* AB#1669 — the takeoff chip beside a quantity: the working is its tooltip. Amber while an approximate figure waits,
   because the amount beside it is still on the stated quantity. */
.est-takeoff-chip[b-h5mwmolj4w] {
    display: inline-block;
    margin-left: .3rem;
    padding: .05rem .4rem;
    border-radius: 999px;
    background: var(--ft-orange-100);
    color: var(--ft-navy);
    font-size: .68rem;
    font-weight: 600;
    white-space: nowrap;
    cursor: help;
}

.est-takeoff-chip-waiting[b-h5mwmolj4w] {
    background: var(--ft-amber-bg);
    color: var(--ft-amber-text);
}
/* /Components/Pages/Estimates/ImportProposalsLog.razor.rz.scp.css */
/* AB#1874 — the proposals-log importer. Scoped, so nothing here reaches another estimating screen. */

.ipl[b-lq2g18jxxs] {
    display: flex;
    flex-direction: column;
    gap: 1rem;
    max-width: 68rem;
}

.ipl-crumb[b-lq2g18jxxs] {
    font-size: .875rem;
    text-decoration: none;
}

.ipl-card[b-lq2g18jxxs] {
    padding: 1rem 1.25rem;
}

.ipl-h2[b-lq2g18jxxs] {
    font-size: 1rem;
    font-weight: 600;
    margin: 0 0 .25rem;
}

.ipl-muted[b-lq2g18jxxs] {
    color: var(--ft-text-muted, #5b6472);
    font-size: .875rem;
    margin: .25rem 0;
}

.ipl-file[b-lq2g18jxxs] {
    display: flex;
    flex-direction: column;
    gap: .35rem;
    font-weight: 600;
}

.ipl-include[b-lq2g18jxxs] {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    font-weight: 400;
}

.ipl-table td[b-lq2g18jxxs] {
    vertical-align: top;
    padding: .4rem .6rem;
}

/* A row still waiting on a person. Marked with a LEFT BORDER and its own sentence rather than by colour alone:
   the sentence is the control, and the bar is what finds it on a long list. */
.ipl-needs[b-lq2g18jxxs] {
    border-left: 3px solid var(--ft-warning, #b8860b);
}

.ipl-flag[b-lq2g18jxxs] {
    display: inline-block;
    font-size: .8125rem;
    color: var(--ft-warning-text, #7a5a00);
}

.ipl-fallback[b-lq2g18jxxs] {
    display: flex;
    flex-direction: column;
    gap: .35rem;
    margin-top: .75rem;
    max-width: 24rem;
}

/* AB#2275 — the other words' sub-steps, and the per-outcome counts of what the rows will record. */
.ipl-h3[b-lq2g18jxxs] {
    font-size: .9375rem;
    font-weight: 600;
    margin: .75rem 0 .25rem;
}

.ipl-counts[b-lq2g18jxxs] {
    display: flex;
    flex-wrap: wrap;
    gap: .25rem 1.25rem;
    list-style: none;
    margin: .25rem 0;
    padding: 0;
}

.ipl-rows summary[b-lq2g18jxxs] {
    cursor: pointer;
    margin: .5rem 0;
}

.ipl-done[b-lq2g18jxxs] {
    font-weight: 600;
    margin: 0 0 .35rem;
}

.ipl-refused[b-lq2g18jxxs] {
    font-weight: 600;
    margin: 0 0 .35rem;
}

@media (prefers-color-scheme: dark) {
    .ipl-muted[b-lq2g18jxxs] { color: var(--ft-text-muted, #9aa4b2); }
    .ipl-flag[b-lq2g18jxxs] { color: var(--ft-warning-text, #e2b64d); }
}
/* /Components/Pages/Estimates/PackAddDocuments.razor.rz.scp.css */
/* AB#2350 — "Add documents" on Pack review. Its own scoped sheet: PackReview's .pr-* rules are scoped to THAT component
   and do not reach markup rendered here, so the card's frame is restated in this file's own names, with the same tokens.
   Every colour is a token declared in both themes (app.css), never a var(--x, #hex) fallback. */

.pad-card[b-3f0fbh9dzv] {
    padding: 0;
    overflow: hidden;
}

.pr-card-hd[b-3f0fbh9dzv] {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: .75rem;
    padding: .9rem 1.25rem;
    border-bottom: 1px solid var(--ft-border-soft);
    font-size: .875rem;
    font-weight: 600;
    color: var(--ft-navy);
}

.pad-body[b-3f0fbh9dzv] {
    padding: 1rem 1.25rem;
    display: flex;
    flex-direction: column;
    gap: .75rem;
    min-width: 0;
}

.pad-intro[b-3f0fbh9dzv] {
    margin: 0;
    color: var(--ft-text-muted);
    font-size: .83rem;
    line-height: 1.55;
}

.pad-pick .ft-hint[b-3f0fbh9dzv],
.pad-chosen[b-3f0fbh9dzv],
.pad-line[b-3f0fbh9dzv] {
    overflow-wrap: anywhere;
}

.pad-line[b-3f0fbh9dzv] {
    display: flex;
    align-items: center;
    gap: .4rem;
}

.pad-error[b-3f0fbh9dzv] {
    padding: .65rem .85rem;
    border-left: 3px solid var(--ft-red);
    background: var(--ft-red-bg);
    color: var(--ft-red-text);
    font-size: .83rem;
    line-height: 1.5;
}

.pad-done[b-3f0fbh9dzv] {
    display: flex;
    flex-direction: column;
    gap: .55rem;
    align-items: flex-start;
    font-size: .83rem;
    color: var(--ft-navy);
    line-height: 1.5;
}

.pad-done p[b-3f0fbh9dzv] { margin: 0; }

.pad-count[b-3f0fbh9dzv] { font-weight: 600; }

.pad-sub[b-3f0fbh9dzv] {
    margin: 0;
    padding: 0;
    color: var(--ft-text-muted);
    font-size: .8rem;
    overflow-wrap: anywhere;
}

.pad-sub ul[b-3f0fbh9dzv],
ul.pad-sub[b-3f0fbh9dzv] {
    margin: .25rem 0 0;
    padding-left: 1.1rem;
}

.pad-sub-title[b-3f0fbh9dzv] {
    font-weight: 600;
    color: var(--ft-amber-text);
}

.pad-body > .ft-btn[b-3f0fbh9dzv] {
    align-self: flex-start;
}
/* /Components/Pages/Estimates/PackReview.razor.rz.scp.css */
/* ═══════════════════════════════════════════════════════════════════════════════════════════════
   Pack review (AB#1735), as a LAYOUT.

   Its own file, and that is the seam: `app.css` is the one stylesheet three lanes would all have to edit
   to do UI at once, and a merge there breaks pages nobody touched. Blazor's scoped CSS gives this page a
   file that cannot reach any other page.

   COLOURS ARE TOKENS, NEVER LITERALS — and on this screen that is not a style preference, it is the
   reason the wireframe reproduces for free. The light palette in app.css already IS artboard 03's
   palette, value for value:

       --ft-blue-bg   #e7eefc = the mockup's Bid form pill        --ft-blue-text   #1d4fb0
       --ft-purple-bg #efeafb = its Specification pill            --ft-purple-text #6d49c9
       --ft-teal-bg   #dff4f2 = its Drawings pill                 --ft-teal-text   #0b6e66
       --ft-amber-bg  #fbf1dc = its Addendum / Minutes / RFI pill --ft-amber-text  #92600a
       --ft-red-bg    #fdecea = its "Fix before pricing" pill     --ft-red-text    #b42318
       --ft-primary   #2d6be4 = its accent

   So the whole colour scheme below costs nothing and the dark theme comes free. A hard-coded hex here
   would have matched the screenshot exactly and been wrong at night.

   WHAT THIS FILE MAY BE TRUSTED WITH. bUnit never loads a stylesheet, so a rule swallowed here is
   invisible to every component test — this codebase has shipped that defect. The claims that carry
   MEANING through colour (the kind chips, the severity chips) are therefore asserted on the COMPUTED
   style in PackReviewScreenTests, resolved through this file and app.css together.
   ═══════════════════════════════════════════════════════════════════════════════════════════════ */

/* ── the page ──────────────────────────────────────────────────────────────────────────────────
   1200px, the same as the workspace: the shell caps .ft-main-content at 1280px with 2.5rem of padding
   each side, so 1200 is the whole of what is on offer and anything larger silently does nothing. */
.pr[b-j4b3z61d3p] {
    max-width: none;   /* AB#1773 W4: fluid */
}

.pr-head[b-j4b3z61d3p] {
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
    gap: 1.5rem;
    flex-wrap: wrap;
    margin-bottom: 1.25rem;
}

.pr-head-text[b-j4b3z61d3p] {
    min-width: 0;
}

.pr-crumbs[b-j4b3z61d3p] {
    display: flex;
    align-items: center;
    gap: .4rem;
    font-size: .8rem;
    color: var(--ft-text-faint);
    margin-bottom: .5rem;
    flex-wrap: wrap;
}

.pr-crumbs a[b-j4b3z61d3p] {
    color: var(--ft-text-faint);
    text-decoration: none;
}

.pr-crumbs a:hover[b-j4b3z61d3p] { color: var(--ft-primary); }

.pr-h1[b-j4b3z61d3p] {
    margin: 0;
    font-size: 1.5rem;
    font-weight: 700;
    letter-spacing: -.025em;
    color: var(--ft-navy);
}

.pr-sub[b-j4b3z61d3p] {
    margin: .25rem 0 0;
    color: var(--ft-text-muted);
    font-size: .875rem;
}

.pr-muted[b-j4b3z61d3p] {
    color: var(--ft-text-muted);
    line-height: 1.55;
}

/* ── seven and five ────────────────────────────────────────────────────────────────────────────
   The wireframe's split. minmax(0, …) on both tracks and not 7fr 5fr alone: a grid track defaults to
   min-content, and one unbreakable file name — real packs carry them — would otherwise push the column
   past the viewport and take the right-hand cards off the edge of the screen. The workspace's own
   stylesheet carries the same note for the same reason; this is the line that makes the split hold. */
.pr-split[b-j4b3z61d3p] {
    display: grid;
    grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
    gap: 1.25rem;
    align-items: start;
}

.pr-col[b-j4b3z61d3p] {
    display: flex;
    flex-direction: column;
    gap: 1.25rem;
    min-width: 0;
}

/* 1100px is the shell's own breakpoint — the fixed sidebar becomes a drawer there — so the split
   collapses on the same line rather than inventing a second one. */
@media (max-width: 1100px) {
    .pr-split[b-j4b3z61d3p] {
        grid-template-columns: minmax(0, 1fr);
    }
}

/* ── the cards ─────────────────────────────────────────────────────────────────────────────────
   Rows are separated by their own top border rather than by padding on the card, so a row can be
   full-bleed the way the wireframe draws it. */
.pr-card[b-j4b3z61d3p] {
    padding: 0;
    overflow: hidden;
}

.pr-card-hd[b-j4b3z61d3p] {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: .75rem;
    padding: .9rem 1.25rem;
    border-bottom: 1px solid var(--ft-border-soft);
    font-size: .875rem;
    font-weight: 600;
    color: var(--ft-navy);
}

.pr-hd-note[b-j4b3z61d3p] {
    font-weight: 400;
    font-size: .8rem;
    color: var(--ft-text-muted);
    text-align: right;
}

.pr-row[b-j4b3z61d3p] {
    display: flex;
    align-items: flex-start;
    gap: .75rem;
    padding: .7rem 1.25rem;
    font-size: .85rem;
    color: var(--ft-navy);
    margin: 0;
}

.pr-row + .pr-row[b-j4b3z61d3p] {
    border-top: 1px solid var(--ft-border-soft);
}

.pr-pad[b-j4b3z61d3p] {
    padding: 1rem 1.25rem;
}

.pr-empty[b-j4b3z61d3p] {
    margin: 0 0 .75rem;
    font-size: .83rem;
}

.pr-empty:last-child[b-j4b3z61d3p] { margin-bottom: 0; }

/* ── chips ─────────────────────────────────────────────────────────────────────────────────────
   The kind chip is the scanning surface: eight files sort into bid form / specification / drawings /
   the-things-that-change-the-job at a glance instead of by reading eight names. Colour is never the
   only carrier — every chip keeps its word, so this survives a monochrome screen and colour blindness.

   background-color and not the `background` shorthand. Measured against AngleSharp.Css 1.0.1: a var()
   resolves in the longhand and comes back EMPTY inside the shorthand, so the computed-style assertions
   in PackReviewScreenTests would go vacuous — a broken instrument reading as a missing tint. */
.pr-chip[b-j4b3z61d3p] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    min-width: 5.5rem;
    padding: .18rem .6rem;
    border-radius: 999px;
    font-size: .72rem;
    font-weight: 600;
    line-height: 1.35;
    white-space: nowrap;
    background-color: var(--ft-surface-2);
    color: var(--ft-text-muted);
}

/* The sheet the estimate was built from. The strongest thing in the pack, and the only one whose rows
   the estimator is about to price. */
.pr-chip-bidform[b-j4b3z61d3p] {
    background-color: var(--ft-blue-bg);
    color: var(--ft-blue-text);
}

.pr-chip-spec[b-j4b3z61d3p] {
    background-color: var(--ft-purple-bg);
    color: var(--ft-purple-text);
}

.pr-chip-drawings[b-j4b3z61d3p] {
    background-color: var(--ft-teal-bg);
    color: var(--ft-teal-text);
}

/* Addendum, minutes, RFI — one colour, because they are one category to an estimator: documents that
   CHANGE what the bid form said. An addendum that moves two lines is the reason a bid is re-priced. */
.pr-chip-change[b-j4b3z61d3p] {
    background-color: var(--ft-amber-bg);
    color: var(--ft-amber-text);
}

/* A finding that moves money, or an instruction hidden in a cell aimed at us. */
.pr-chip-bad[b-j4b3z61d3p] {
    background-color: var(--ft-red-bg);
    color: var(--ft-red-text);
}

.pr-pill[b-j4b3z61d3p] {
    display: inline-flex;
    padding: .18rem .6rem;
    border-radius: 999px;
    font-size: .72rem;
    font-weight: 600;
    white-space: nowrap;
    background-color: var(--ft-surface-2);
    color: var(--ft-text-muted);
}

.pr-pill-bad[b-j4b3z61d3p] {
    background-color: var(--ft-red-bg);
    color: var(--ft-red-text);
}

.pr-pill-good[b-j4b3z61d3p] {
    background-color: var(--ft-green-bg);
    color: var(--ft-green-text);
}

/* ── a document row ────────────────────────────────────────────────────────────────────────────
   The client's own file name is theirs and is never shortened, so it wraps mid-token if it has to —
   real pack names run to "EOR Drawings/DWG- 2026-06-15 … CATWALKS COMBINED.pdf" with no break
   opportunity a browser will take on its own. */
.pr-doc-body[b-j4b3z61d3p] {
    flex: 1 1 auto;
    min-width: 0;
}

.pr-doc-name[b-j4b3z61d3p] {
    overflow-wrap: anywhere;
    line-height: 1.45;
}

/* AB#2260 — the file name opens the file. Underlined so it reads as a link without colour alone. */
.pr-doc-open[b-j4b3z61d3p] {
    color: var(--ft-primary);
    text-decoration: underline;
    text-underline-offset: 2px;
}

.pr-doc-open:hover[b-j4b3z61d3p],
.pr-doc-open:focus-visible[b-j4b3z61d3p] {
    color: var(--ft-navy);
}

.pr-doc-why[b-j4b3z61d3p] {
    margin-top: .15rem;
    font-size: .78rem;
    color: var(--ft-text-faint);
    line-height: 1.45;
}

.pr-why-label[b-j4b3z61d3p] { font-weight: 600; }

.pr-tag[b-j4b3z61d3p] {
    display: inline-block;
    margin-left: .35rem;
    padding: .05rem .4rem;
    border-radius: 999px;
    font-size: .7rem;
    font-weight: 500;
    background-color: var(--ft-surface-2);
    color: var(--ft-text-muted);
}

.pr-tag-warn[b-j4b3z61d3p] {
    background-color: var(--ft-amber-bg);
    color: var(--ft-amber-text);
}

/* The one fact the row states, right-aligned against the name the way the wireframe sets it. */
.pr-fact[b-j4b3z61d3p] {
    flex: 0 0 auto;
    max-width: 14rem;
    text-align: right;
    font-size: .8rem;
    color: var(--ft-text-muted);
    line-height: 1.4;
}

/* "Nothing readable inside" and "removed under the retention policy" are not neutral facts — the first
   means the kind beside it rests on a file name, the second that the file is gone. */
.pr-fact-warn[b-j4b3z61d3p] {
    color: var(--ft-amber-text);
    font-weight: 600;
}

/* AB#2208 — what the upload held back: a block under the documents, not rows among them. */
.pr-held[b-j4b3z61d3p] {
    display: block;
}

.pr-held-title[b-j4b3z61d3p] {
    font-weight: 600;
    color: var(--ft-amber-text);
}

.pr-held-list[b-j4b3z61d3p] {
    margin: .35rem 0 0;
    padding-left: 1.1rem;
    color: var(--ft-text-muted);
    font-size: .8rem;
    line-height: 1.5;
}

/* ── a finding ─────────────────────────────────────────────────────────────────────────────────── */
.pr-finding-body[b-j4b3z61d3p] {
    flex: 1 1 auto;
    min-width: 0;
}

.pr-finding-what[b-j4b3z61d3p] {
    font-weight: 600;
    line-height: 1.4;
}

.pr-finding-why[b-j4b3z61d3p] {
    margin-top: .1rem;
    font-size: .8rem;
    color: var(--ft-text-muted);
    line-height: 1.45;
}

/* The action. Small, and it does not shrink — a button that wraps to two lines beside a two-line
   explanation stops reading as one thing to press. */
.pr-action[b-j4b3z61d3p] {
    flex: 0 0 auto;
    padding: .3rem .7rem;
    font-size: .78rem;
    white-space: nowrap;
}

/* Where there is no action, the sentence saying why sits in the same place the button would have. It is
   deliberately the same column: a silent blank there reads as "we could do something and chose not to". */
.pr-outcome[b-j4b3z61d3p] {
    flex: 0 0 auto;
    max-width: 12rem;
    text-align: right;
    font-size: .78rem;
    color: var(--ft-text-muted);
    line-height: 1.4;
}

.pr-notes[b-j4b3z61d3p] {
    display: block;
}

.pr-notes-title[b-j4b3z61d3p] {
    font-size: .78rem;
    font-weight: 600;
    color: var(--ft-text-muted);
    margin-bottom: .3rem;
}

.pr-notes-list[b-j4b3z61d3p] {
    margin: 0;
    padding-left: 1.1rem;
    font-size: .8rem;
    color: var(--ft-text-muted);
    line-height: 1.5;
}

/* ── key dates ─────────────────────────────────────────────────────────────────────────────────
   Tabular numerals so a column of dates lines up, which is the whole reason a date column is readable
   at a glance. It matters more here than it looks: this card is the one an estimator checks last thing
   before deciding whether the bid can still be delivered. */
.pr-date[b-j4b3z61d3p] {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 1rem;
    padding-top: .75rem;
    border-top: 1px solid var(--ft-border-soft);
}

.pr-date-label[b-j4b3z61d3p] {
    font-weight: 600;
    font-size: .85rem;
    color: var(--ft-navy);
}

.pr-date-cite[b-j4b3z61d3p] {
    font-size: .75rem;
    color: var(--ft-text-faint);
    line-height: 1.4;
}

.pr-date-when[b-j4b3z61d3p] {
    font-variant-numeric: tabular-nums;
    font-size: .85rem;
    color: var(--ft-navy);
    white-space: nowrap;
}

.pr-continue[b-j4b3z61d3p] {
    display: flex;
    justify-content: flex-end;
}

/* ── one column ────────────────────────────────────────────────────────────────────────────────
   Below the split, a document's fact under its name rather than beside it: a 14rem right-aligned
   column and a wrapping file name in the same 4-inch row is how "104 rows" ends up on a line of its
   own with nothing to attach it to. */
@media (max-width: 700px) {
    .pr-row[b-j4b3z61d3p] {
        flex-wrap: wrap;
    }

    .pr-fact[b-j4b3z61d3p],
    .pr-outcome[b-j4b3z61d3p] {
        max-width: none;
        text-align: left;
        flex-basis: 100%;
    }
}

/* AB#1667 (lane 3, batch AD) — the door to the drawing sheet index. Inside the documents card because the
   sheets ARE those documents opened up; a button in its own card would read as a separate feature. */
.pr-sheets[b-j4b3z61d3p] {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    flex-wrap: wrap;
    font-size: 0.8125rem;
}

/* AB#1815 — the reserved Sheets slot when there are no drawings. It carries no control, so it needs a
   label doing the job the button's own words did: without one the row is a floating sentence and reads
   as a footnote rather than as the step it is holding open. */
.pr-slot-label[b-j4b3z61d3p] {
    font-weight: 650;
    color: var(--ft-navy);
    white-space: nowrap;
    flex: 0 0 auto;
}

/* ── AB#1815: the honest empty state ───────────────────────────────────────────────────────────
   A block rather than a sentence: the lede, the three absences, then what still works. It is a
   `.pr-row`, so it keeps the card's padding and the separator above the Sheets slot below it, and it
   stacks instead of sitting on one line. */
.pr-empty-block[b-j4b3z61d3p] {
    display: block;
}

.pr-empty-lede[b-j4b3z61d3p] {
    margin: 0;
    font-size: .85rem;
    line-height: 1.55;
    max-width: 52rem;
}

.pr-empty-list[b-j4b3z61d3p] {
    margin: .55rem 0 0;
    padding-left: 1.1rem;
    font-size: .83rem;
    line-height: 1.55;
    color: var(--ft-navy);
    max-width: 52rem;
}

.pr-empty-list li + li[b-j4b3z61d3p] {
    margin-top: .25rem;
}

/* The one positive claim on the block, and it is the reason the block exists rather than a list of
   absences: on a seeded bid nearly everything still works, and a screen that only enumerates what is
   missing reads as a broken bid. Ruled off so it is not mistaken for a fourth absence. */
.pr-empty-can[b-j4b3z61d3p] {
    margin: .6rem 0 0;
    padding-top: .55rem;
    border-top: 1px solid var(--ft-border-soft);
    font-size: .83rem;
    line-height: 1.55;
    max-width: 52rem;
}
/* /Components/Pages/Estimates/QuestionResolutionControls.razor.rz.scp.css */
/* ═══════════════════════════════════════════════════════════════════════════════════════════════
   The two acts on one question (AB#1775), as a LAYOUT (AB#1813).

   WHY THIS FILE EXISTS AT ALL. Every rule below was an inline `style` attribute until AB#1813. That was
   fine while the component was two buttons; it stopped being fine when Steve's finding was that the cards
   are TEXT-HEAVY and the two presses do not stand out of the prose above them. Separating them wants a
   rule, a little more air and a hover state, and none of that belongs in a `style=` attribute.

   It is a `.razor.css` and not `app.css` for the reason every estimating surface has had one since
   AB#1732: `app.css` is the one stylesheet three lanes would all have to edit to do UI at once, and a
   merge there breaks pages nobody touched. Blazor scopes this file to this component, so it cannot reach
   the two pages that host it.

   COLOURS ARE TOKENS, NEVER LITERALS, with the fallbacks the workspace's own gate strip uses — so the
   dark theme comes free and the two pages do not argue about what green means.

   WHAT THIS FILE MAY BE TRUSTED WITH: layout and colour, and nothing else. bUnit loads no stylesheet, so
   a rule swallowed here is invisible to every component test — this codebase has shipped that defect. The
   labels, the testids, the disabled-while-saving rule and the Save-on-blank refusal are all markup, and
   all asserted there.
   ═══════════════════════════════════════════════════════════════════════════════════════════════ */

/* The action row. The top rule is the whole point: a question card is a sentence, a "why it matters", a
   citation and sometimes a link, and before this the two presses sat in that stack looking like more of
   it. */
.qres[b-s9gkbo69sp] {
    display: flex;
    flex-wrap: wrap;
    gap: .4rem;
    align-items: center;
    margin-top: .6rem;
    padding-top: .55rem;
    border-top: 1px solid var(--ft-border);
}

.qres-btn[b-s9gkbo69sp] {
    font-size: .78rem;
    padding: .25rem .7rem;
}

/* ── the state, after a press ─────────────────────────────────────────────────────────────────
   A chip that says which of the two acts happened, then the recorded words beside it. The words are
   the estimator's own and are never shortened — they wrap. */
.qres-chip[b-s9gkbo69sp] {
    display: inline-block;
    padding: .12rem .5rem;
    border-radius: 999px;
    font-size: .72rem;
    font-weight: 600;
    white-space: nowrap;
    border: 1px solid var(--ft-border-strong);
    color: var(--ft-text-muted);
}

/* Green for the one that carries an answer, neutral for the one that carries a decision not to ask.
   The words are on both chips, so colour is never the only carrier.

   `--ft-green-text` and NOT `--ft-success`: the inline style this replaced said
   `var(--ft-success,#16a34a)`, and --ft-success is declared in neither theme — so that chip has always
   rendered the hard-coded fallback, which is a light-theme green sitting on a dark card at night.
   --ft-green-text is declared in both (#0f7a4d light, #00d685 dark) and is what every other estimating
   surface already uses for exactly this. Reported to lane 0 rather than swept: the same
   `var(--ft-success,…)` / `var(--ft-danger,…)` pattern is on other estimating components. */
.qres-chip-answered[b-s9gkbo69sp] {
    border-color: var(--ft-green-text);
    color: var(--ft-green-text);
}

.qres-chip-skipped[b-s9gkbo69sp] {
    border-color: var(--ft-border-strong);
}

.qres-said[b-s9gkbo69sp] {
    flex: 1 1 16rem;
    min-width: 12rem;
    font-size: .85rem;
    color: var(--ft-text-muted);
    line-height: 1.5;
    overflow-wrap: anywhere;
}

/* ── the one little form, for both acts ───────────────────────────────────────────────────────
   Full width of the card, because what a client said is a sentence and not a word. */
.qres-form[b-s9gkbo69sp] {
    flex: 1 1 100%;
    display: flex;
    flex-direction: column;
    gap: .35rem;
}

.qres-label[b-s9gkbo69sp] {
    font-size: .8rem;
    font-weight: 600;
    color: var(--ft-navy);
}

.qres-box[b-s9gkbo69sp] {
    width: 100%;
    font: inherit;
    padding: .4rem .55rem;
    border: 1px solid var(--ft-border-strong);
    border-radius: 6px;
    background: var(--ft-surface);
    color: var(--ft-text);
}

.qres-box:focus-visible[b-s9gkbo69sp] {
    outline: 2px solid var(--ft-primary);
    outline-offset: 1px;
}

.qres-hint[b-s9gkbo69sp] {
    font-size: .8rem;
    color: var(--ft-text-muted);
    line-height: 1.5;
    max-width: 52rem;
}

.qres-actions[b-s9gkbo69sp] {
    display: flex;
    gap: .4rem;
    flex-wrap: wrap;
}

/* AB#1882 — where the answer came from: the form (kind, reference, date) and the recorded citation. */
.qres-source-form[b-s9gkbo69sp] {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: .5rem .75rem;
    margin: .5rem 0 .4rem;
    padding: 0;
    border: 0;
}

.qres-source-form > legend[b-s9gkbo69sp] { flex-basis: 100%; padding: 0; }

.qres-source-field[b-s9gkbo69sp] {
    display: flex;
    flex-direction: column;
    gap: .15rem;
    font-size: .78rem;
    color: var(--ft-text-muted);
}

.qres-source-kind[b-s9gkbo69sp],
.qres-source-ref[b-s9gkbo69sp],
.qres-source-date[b-s9gkbo69sp] {
    font-size: .82rem;
    padding: .25rem .4rem;
    border: 1px solid var(--ft-border-strong);
    border-radius: 6px;
    background: var(--ft-surface);
    color: var(--ft-text);
}

.qres-source-ref[b-s9gkbo69sp] { min-width: 12rem; }

.qres-source[b-s9gkbo69sp] {
    flex-basis: 100%;
    font-size: .78rem;
    color: var(--ft-text-muted);
}
/* /Components/Pages/Estimates/RevisionCompare.razor.rz.scp.css */
/* AB#1654 — the revision compare screen.
 *
 * SCOPED, and that is what lets three lanes build UI at once: Blazor CSS isolation rewrites every selector
 * here with this component's own attribute, so nothing in this file can reach another page and nothing in
 * another page's file can reach this one. wwwroot/app.css is the shared surface and is deliberately NOT
 * touched.
 *
 * COLOURS ARE SET WITH background-color, NEVER the background shorthand, and that is load-bearing rather
 * than pedantry. RevisionCompareScreenTests asserts the tint on an added row from the RESOLVED style, and
 * AngleSharp.Css 1.0.1 — the engine bUnit brings — resolves var() in the background-color LONGHAND and
 * returns empty for the same var() inside the `background` shorthand. Measured both ways, on :root, on html
 * and on html[data-theme="light"]: only the longhand comes back. Written as a shorthand, the rule would be
 * correct in a browser and untestable here, and this file's whole reason for being asserted is that a
 * swallowed CSS rule is invisible to every DOM test.
 *
 * EVERY colour is a --ft-* token. The app is dark-first with a light override (html[data-theme="light"]),
 * and the wireframe is the light theme — its literals map onto the tokens exactly: #fdecea/#b42318 are
 * --ft-red-bg/--ft-red-text, #e6f4ec/#0f7a4d are --ft-green-bg/--ft-green-text, #fbf1dc/#92600a are
 * --ft-amber-bg/--ft-amber-text. Writing the literals would have produced a screen that is unreadable in
 * the theme most of the app is used in.
 */

.rc[b-8r8ihz9wmh] {
    display: flex;
    flex-direction: column;
    gap: 1rem;
    max-width: none;   /* AB#1773 W4: fluid; the table takes the window, the description column benefits most */
}

.rc-pad[b-8r8ihz9wmh] { padding: 1.25rem 1.5rem; }

/* ── header ──────────────────────────────────────────────────────────────────────────────────── */

.rc-head[b-8r8ihz9wmh] {
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
    gap: 1.5rem;
    flex-wrap: wrap;
}

.rc-head-text[b-8r8ihz9wmh] { min-width: 0; }

.rc-crumbs[b-8r8ihz9wmh] {
    font-size: .8rem;
    color: var(--ft-text-faint);
    margin-bottom: .5rem;
    display: flex;
    gap: .4rem;
    flex-wrap: wrap;
}

.rc-crumbs a[b-8r8ihz9wmh] { color: var(--ft-text-faint); text-decoration: none; }
.rc-crumbs a:hover[b-8r8ihz9wmh] { color: var(--ft-primary); text-decoration: underline; }

.rc-h1[b-8r8ihz9wmh] {
    margin: 0;
    font-size: 1.5rem;
    font-weight: 700;
    letter-spacing: -.025em;
    color: var(--ft-navy);
}

.rc-sub[b-8r8ihz9wmh] {
    margin: .25rem 0 0;
    color: var(--ft-text-muted);
    font-size: .875rem;
    line-height: 1.5;
    max-width: 52rem;
}

.rc-muted[b-8r8ihz9wmh] { color: var(--ft-text-muted); font-size: .9rem; line-height: 1.55; max-width: 46rem; }

/* The pair, as the estimator names it. */
.rc-pair[b-8r8ihz9wmh] {
    display: flex;
    gap: .6rem;
    align-items: center;
    font-size: .83rem;
    flex-wrap: wrap;
}

.rc-pill[b-8r8ihz9wmh] {
    padding: .45rem .9rem;
    border: 1px solid var(--ft-border);
    border-radius: var(--ft-radius-sm);
    background-color: var(--ft-surface);
    color: var(--ft-text);
    white-space: nowrap;
}

.rc-pill-on[b-8r8ihz9wmh] {
    border-color: var(--ft-primary);
    background-color: var(--ft-blue-bg);
    color: var(--ft-blue-text);
    font-weight: 600;
}

.rc-arrow[b-8r8ihz9wmh] { color: var(--ft-text-faint); }

/* ── picker ──────────────────────────────────────────────────────────────────────────────────── */

.rc-picker[b-8r8ihz9wmh] { display: flex; flex-direction: column; gap: .55rem; }

.rc-picker-row[b-8r8ihz9wmh] {
    display: flex;
    align-items: center;
    gap: .4rem;
    flex-wrap: wrap;
}

.rc-picker-label[b-8r8ihz9wmh] {
    font-size: .7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .08em;
    color: var(--ft-text-faint);
    min-width: 4.5rem;
}

.rc-opt[b-8r8ihz9wmh] {
    padding: .3rem .7rem;
    border: 1px solid var(--ft-border);
    border-radius: var(--ft-radius-sm);
    background-color: var(--ft-surface);
    color: var(--ft-text);
    font-size: .8rem;
    text-decoration: none;
    white-space: nowrap;
}

.rc-opt:hover[b-8r8ihz9wmh] { border-color: var(--ft-primary); color: var(--ft-primary); }

.rc-opt-on[b-8r8ihz9wmh] {
    border-color: var(--ft-primary);
    background-color: var(--ft-blue-bg);
    color: var(--ft-blue-text);
    font-weight: 600;
}

/* The changed / all-lines view pills (AB#1773). Same shape as the picker chips so the screen has one kind
   of pill; buttons rather than links, because they change the VIEW of one comparison, not the pair. */
.rc-view[b-8r8ihz9wmh] {
    display: flex;
    align-items: center;
    gap: .4rem;
    flex-wrap: wrap;
}

.rc-view button.rc-opt[b-8r8ihz9wmh] {
    cursor: pointer;
    font-family: inherit;
    line-height: 1.4;
}

/* ── the options ─────────────────────────────────────────────────────────────────────────────────
 *
 * AB#1789 — Good / Better / Best. Three fully priced scopes for one job, laid out as peers because that is
 * what they are: RCG prices each sheet independently and none of them is a delta from another, so a layout
 * that made one primary and the others adjustments to it would be a claim about the data that is false.
 *
 * NOT inside a <details> and not behind a tab. bUnit renders a collapsed disclosure's children into the DOM,
 * so a panel hidden that way is green across the whole Dashboard suite while a real browser paints nothing
 * (AB#1753 shipped exactly that, and four Playwright assertions on correct code would have failed). The one
 * number a client is choosing between does not belong behind a click in any case.
 *
 * Colours are --ft-* tokens set with background-color longhand, for the reason at the top of this file. */

.rc-tiers[b-8r8ihz9wmh] { display: flex; flex-direction: column; gap: 1rem; }

.rc-tiers-head[b-8r8ihz9wmh] { display: flex; flex-direction: column; gap: .3rem; }

.rc-h2[b-8r8ihz9wmh] {
    margin: 0;
    font-size: 1.05rem;
    font-weight: 700;
    letter-spacing: -.015em;
    color: var(--ft-navy);
}

/* auto-fit rather than a fixed count: two options and five are both real (25-174 has three, and a
   best-and-final on two scenarios has two), and a hard `repeat(3, …)` would strand one tile on a row. */
.rc-tier-grid[b-8r8ihz9wmh] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
    gap: .9rem;
}

.rc-tier[b-8r8ihz9wmh] {
    display: flex;
    flex-direction: column;
    gap: .2rem;
    padding: .9rem 1rem 1rem;
    border: 1px solid var(--ft-border);
    border-radius: .6rem;
    background-color: var(--ft-surface);
}

/* The two in the comparison are marked, not isolated — the others stay fully legible, because the reader is
   choosing between all of them and dimming the rest would answer the question for them. */
.rc-tier-on[b-8r8ihz9wmh] {
    border-color: var(--ft-primary);
    box-shadow: inset 0 0 0 1px var(--ft-primary);
}

.rc-tier-name[b-8r8ihz9wmh] {
    display: flex;
    align-items: baseline;
    gap: .45rem;
    flex-wrap: wrap;
}

/* The client's own word for the option. Never truncated with an ellipsis: "Like for like" and "Like for
   like (partial)" are different scopes and a cut name would merge them on sight. */
.rc-tier-title[b-8r8ihz9wmh] {
    font-size: 1rem;
    font-weight: 700;
    color: var(--ft-navy);
    overflow-wrap: anywhere;
}

.rc-tier-rev[b-8r8ihz9wmh] {
    font-size: .7rem;
    font-weight: 600;
    letter-spacing: .04em;
    color: var(--ft-text-faint);
    border: 1px solid var(--ft-border);
    border-radius: .3rem;
    padding: .05rem .3rem;
}

.rc-tier-l[b-8r8ihz9wmh] {
    font-size: .68rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .08em;
    color: var(--ft-text-faint);
    margin-top: .45rem;
}

.rc-tier-v[b-8r8ihz9wmh] {
    font-size: 1.35rem;
    font-weight: 700;
    letter-spacing: -.02em;
    font-variant-numeric: tabular-nums;
    color: var(--ft-navy);
}

.rc-tier-delta[b-8r8ihz9wmh] { font-size: .82rem; font-weight: 600; }

.rc-tier-warn[b-8r8ihz9wmh] { font-size: .78rem; color: var(--ft-amber-text); margin-top: .2rem; }

.rc-tier-cta[b-8r8ihz9wmh] { margin-top: .7rem; align-self: flex-start; font-size: .82rem; }

/* ── the summary strip ───────────────────────────────────────────────────────────────────────── */

/* Six tiles since AB#1773 added "Changed rows" beside Net. At the page's 1180px that is ~190px each, which
   the largest value ("−$19,925 · −0.8%") fits; below that they fold to three then two. */
.rc-strip[b-8r8ihz9wmh] {
    padding: .9rem 1.4rem;
    display: grid;
    grid-template-columns: repeat(6, minmax(0, 1fr));
    gap: 1.1rem;
}

@media (max-width: 1100px) {
    .rc-strip[b-8r8ihz9wmh] { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

@media (max-width: 640px) {
    .rc-strip[b-8r8ihz9wmh] { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* "29" carries the weight; "of 253 lines" is the qualifier and reads smaller beside it. */
.rc-kpi-sub[b-8r8ihz9wmh] {
    margin-left: .4rem;
    font-size: .72rem;
    font-weight: 500;
    letter-spacing: 0;
    color: var(--ft-text-muted);
    white-space: nowrap;
}

.rc-kpi-l[b-8r8ihz9wmh] {
    font-size: .68rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .08em;
    color: var(--ft-text-faint);
    margin-bottom: .15rem;
}

.rc-kpi-v[b-8r8ihz9wmh] {
    font-size: 1.15rem;
    font-weight: 700;
    letter-spacing: -.02em;
    font-variant-numeric: tabular-nums;
    color: var(--ft-navy);
}

/* Direction, not decoration. Money going down is read as good on a bid and bad on a total, so the colour
   only ever says which way it went — never whether that is welcome. */
.rc-down[b-8r8ihz9wmh] { color: var(--ft-red-text); }
.rc-up[b-8r8ihz9wmh] { color: var(--ft-green-text); }
.rc-flat[b-8r8ihz9wmh] { color: var(--ft-text-muted); }
.rc-unknown[b-8r8ihz9wmh] { color: var(--ft-text-faint); font-style: italic; }

.rc-caveats[b-8r8ihz9wmh] { display: flex; flex-direction: column; gap: .35rem; }

.rc-caveats p[b-8r8ihz9wmh] {
    margin: 0;
    font-size: .85rem;
    line-height: 1.55;
    color: var(--ft-text-muted);
    max-width: 62rem;
}

.rc-caveats p.rc-warn[b-8r8ihz9wmh] { color: var(--ft-amber-text); }

/* ── the table ───────────────────────────────────────────────────────────────────────────────── */

.rc-table-card[b-8r8ihz9wmh] { overflow: hidden; }

.rc-table[b-8r8ihz9wmh] {
    width: 100%;
    border-collapse: collapse;
}

.rc-th[b-8r8ihz9wmh] {
    font-size: .7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .08em;
    color: var(--ft-text-faint);
    padding: .65rem 1rem;
    border-bottom: 1px solid var(--ft-border);
    text-align: left;
    white-space: nowrap;
}

.rc-td[b-8r8ihz9wmh] {
    padding: .6rem 1rem;
    border-bottom: 1px solid var(--ft-border-soft);
    font-size: .83rem;
    vertical-align: middle;
    font-variant-numeric: tabular-nums;
    color: var(--ft-text);
}

/* A figure never wraps: "168 LF @ $38.00" broken over two lines reads as two facts. The description
   column is the one that gives way (it is clamped), never the numbers. */
.rc-num[b-8r8ihz9wmh] { text-align: right; white-space: nowrap; }
.rc-code[b-8r8ihz9wmh] { font-weight: 600; color: var(--ft-navy); white-space: nowrap; }
.rc-line[b-8r8ihz9wmh] { min-width: 0; }

/* Two lines at most, and the whole description in the element's title (AB#1773, frame G). A long line
   used to grow the row as tall as it liked and the table with it; now the row is bounded and the reader
   hovers for the rest. overflow-wrap:anywhere for the reason .est-desc records — one real line,
   "Mobilization/Demobilization/General Conditions", is a single unbreakable token to a browser. */
.rc-desc[b-8r8ihz9wmh] {
    line-height: 1.45;
    overflow-wrap: anywhere;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.rc-reason[b-8r8ihz9wmh] { color: var(--ft-text-muted); line-height: 1.45; }

.rc-reason-text[b-8r8ihz9wmh] {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    overflow-wrap: anywhere;
}

.rc-w-code[b-8r8ihz9wmh] { width: 4.5rem; }
.rc-w-chip[b-8r8ihz9wmh] { width: 7.5rem; }
.rc-w-side[b-8r8ihz9wmh] { width: 8.5rem; }
.rc-w-delta[b-8r8ihz9wmh] { width: 7rem; }
.rc-w-reason[b-8r8ihz9wmh] { width: 15rem; }

/* The client's own heading over a block of lines — a band, not a row, so it is read as structure. */
.rc-section-td[b-8r8ihz9wmh] {
    padding: .5rem 1rem;
    background-color: var(--ft-surface-2);
    border-bottom: 1px solid var(--ft-border);
    font-size: .7rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--ft-text-muted);
}

/* A recorded reason and a missing one must never look alike. The missing one is a SENTENCE — "No reason was
   recorded" — set apart so it cannot be skimmed as though the column were simply blank. */
.rc-no-reason[b-8r8ihz9wmh] {
    color: var(--ft-text-faint);
    font-style: italic;
}

.rc-alt[b-8r8ihz9wmh] {
    margin-top: .25rem;
    font-size: .75rem;
    color: var(--ft-amber-text);
}

/* AB#1799 — the wording this line used to carry, under the wording it carries now. Muted and clamped to one
   line: it is context for the row above it, not a second line of the bid, and the whole sentence is in the
   title. Struck through because the two sentences are otherwise near-identical on the case this exists for —
   a changed bracket — and an unmarked repetition reads as a duplicate row rather than as a before-and-after. */
.rc-was[b-8r8ihz9wmh] {
    margin-top: .2rem;
    font-size: .75rem;
    color: var(--ft-text-muted);
    text-decoration: line-through;
    text-decoration-thickness: 1px;
    overflow-wrap: anywhere;
    display: -webkit-box;
    -webkit-line-clamp: 1;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/* Added work is tinted across the whole row: it is the one change an estimator scans for, and a chip alone
   makes them read the column to find it. A wash of the green surface token, so it holds in both themes. */
.rc-row-added[b-8r8ihz9wmh] { background-color: var(--ft-green-bg); box-shadow: inset 3px 0 0 var(--ft-green-text); }
.rc-row-removed[b-8r8ihz9wmh] { background-color: var(--ft-red-bg); box-shadow: inset 3px 0 0 var(--ft-red-text); }

/* AB#1773 — three readings. A matched line that moved is highlighted (the amber wash, with the edge bar
   that makes a 253-line sheet scannable at speed); an unchanged line is QUIET: no tint, muted text, so it
   is present for position and nothing else. The old screen had only "added / removed / everything else",
   and "everything else" was both the rate cuts the reader came for and, now, the lines they did not. */
.rc-row-changed[b-8r8ihz9wmh] { background-color: var(--ft-amber-bg); box-shadow: inset 3px 0 0 var(--ft-amber-text); }
.rc-row-quiet .rc-td[b-8r8ihz9wmh] { color: var(--ft-text-muted); }
.rc-row-quiet .rc-code[b-8r8ihz9wmh] { color: var(--ft-text-faint); font-weight: 500; }

.rc-row:hover[b-8r8ihz9wmh] { background-color: var(--ft-surface-2); }
.rc-row-added:hover[b-8r8ihz9wmh] { background-color: var(--ft-green-bg); }
.rc-row-removed:hover[b-8r8ihz9wmh] { background-color: var(--ft-red-bg); }
.rc-row-changed:hover[b-8r8ihz9wmh] { background-color: var(--ft-amber-bg); }

/* ── chips ───────────────────────────────────────────────────────────────────────────────────── */

.rc-chip[b-8r8ihz9wmh] {
    display: inline-flex;
    align-items: center;
    padding: 2px 8px;
    border-radius: 20px;
    font-size: .68rem;
    font-weight: 600;
    white-space: nowrap;
}

.rc-chip-cut[b-8r8ihz9wmh] { background-color: var(--ft-red-bg); color: var(--ft-red-text); }
.rc-chip-warn[b-8r8ihz9wmh] { background-color: var(--ft-amber-bg); color: var(--ft-amber-text); }
.rc-chip-added[b-8r8ihz9wmh] { background-color: var(--ft-green-bg); color: var(--ft-green-text); }
.rc-chip-quiet[b-8r8ihz9wmh] { background-color: var(--ft-surface-2); color: var(--ft-text-muted); }
/* /Components/Pages/Estimates/SheetIndex.razor.rz.scp.css */
/* ═══════════════════════════════════════════════════════════════════════════════════════════════
   The drawing sheet index (AB#1667) and its honesty column (AB#1671).

   ITS OWN FILE, WHICH IS THE SEAM. `app.css` is the one stylesheet several lanes would all have to edit
   to do UI at once, and a merge there breaks pages nobody touched. Blazor's scoped CSS gives this page a
   file that cannot reach any other page — the same rule PackReview.razor.css records.

   COLOURS ARE TOKENS, NEVER LITERALS, so the dark theme comes free and the palette stays the product's:
       --ft-teal-*   the Drawings chip on pack review — a drawn sheet here is the same family
       --ft-amber-*  a scan: readable, but not something a number may come off
       --ft-red-*    reserved for the refusal pill, which is the loudest thing on the page and is
                     therefore also the most common — see the note below
       --ft-green-*  the permitted pill, which today appears on nothing

   THE REFUSAL PILL IS NOT AN ALARM. On this corpus almost every sheet refuses, and a page of red would
   read as a page of errors — the drawings are fine, they simply say not to scale them. So "No" is set in
   the muted neutral, and the REASON beside it carries the meaning. Only a sheet that disagrees with
   itself (a reduced copy) would ever want red, and nothing produces that verdict yet.

   WHAT THIS FILE MAY BE TRUSTED WITH. bUnit never loads a stylesheet, so a rule swallowed here is
   invisible to every component test — this codebase has shipped that defect. Nothing on this page carries
   meaning through colour alone: every chip and every pill has its words.
   ═══════════════════════════════════════════════════════════════════════════════════════════════ */

.si[b-g2x2ti0nnm] {
    max-width: none;
}

.si-pad[b-g2x2ti0nnm] {
    padding: 1.25rem 1.5rem;
}

.si-head[b-g2x2ti0nnm] {
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
    gap: 1.5rem;
    flex-wrap: wrap;
    margin-bottom: 1.25rem;
}

.si-crumbs[b-g2x2ti0nnm] {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.8125rem;
    color: var(--ft-text-muted);
    margin-bottom: 0.375rem;
}

.si-crumbs a[b-g2x2ti0nnm] {
    color: var(--ft-text-muted);
    text-decoration: none;
}

.si-crumbs a:hover[b-g2x2ti0nnm] {
    color: var(--ft-primary);
    text-decoration: underline;
}

.si-h1[b-g2x2ti0nnm] {
    font-size: 1.5rem;
    font-weight: 650;
    margin: 0 0 0.375rem;
}

/* The sentence. Set larger than body text because it is the whole point of the screen: an estimator who
   reads only this line still knows what arrived and what will be refused. */
.si-verdict[b-g2x2ti0nnm] {
    margin: 0;
    max-width: 68ch;
    font-size: 0.9375rem;
    line-height: 1.5;
    color: var(--ft-text);
}

.si-muted[b-g2x2ti0nnm] {
    color: var(--ft-text-muted);
}

.si-warn[b-g2x2ti0nnm] {
    border-left: 3px solid var(--ft-amber-text);
}

.si-note[b-g2x2ti0nnm] {
    margin-bottom: 1rem;
}

.si-note-title[b-g2x2ti0nnm] {
    font-weight: 600;
    margin-bottom: 0.375rem;
}

.si-note-list[b-g2x2ti0nnm] {
    margin: 0.25rem 0 0;
    padding-left: 1.25rem;
    color: var(--ft-text-muted);
    font-size: 0.875rem;
}

/* ── one file ────────────────────────────────────────────────────────────────────────────────── */

.si-file[b-g2x2ti0nnm] {
    margin-bottom: 1rem;
}

.si-file-hd[b-g2x2ti0nnm] {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 1rem;
    padding: 0.75rem 1rem;
    border-bottom: 1px solid var(--ft-border);
    flex-wrap: wrap;
}

.si-file-name[b-g2x2ti0nnm] {
    font-weight: 600;
    word-break: break-word;
}

.si-file-note[b-g2x2ti0nnm] {
    font-size: 0.8125rem;
    color: var(--ft-text-muted);
    white-space: nowrap;
}

.si-row[b-g2x2ti0nnm] {
    padding: 0.75rem 1rem;
    margin: 0;
}

/* ── the sheets ──────────────────────────────────────────────────────────────────────────────────
   A grid rather than a <table> so the honesty column can wrap its sentence without the row collapsing.
   It keeps table ROLES, so it is still a table to a screen reader. On a narrow viewport the grid
   linearises rather than scrolling sideways: the reason column is prose and would be unreadable in a
   120px column. */
.si-table[b-g2x2ti0nnm] {
    display: grid;
    grid-template-columns: 6.5rem minmax(8rem, 1.2fr) 9rem minmax(7rem, 0.9fr) minmax(16rem, 1.6fr);
    align-items: start;
}

.si-tr[b-g2x2ti0nnm] {
    display: contents;
}

.si-tr > *[b-g2x2ti0nnm] {
    padding: 0.625rem 0.75rem;
    border-bottom: 1px solid var(--ft-border);
    font-size: 0.875rem;
    min-width: 0;
    overflow-wrap: anywhere;
}

.si-th > *[b-g2x2ti0nnm] {
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--ft-text-muted);
    background: var(--ft-surface-2);
}

.si-num[b-g2x2ti0nnm] {
    font-weight: 650;
    font-variant-numeric: tabular-nums;
}

.si-scale[b-g2x2ti0nnm] {
    font-variant-numeric: tabular-nums;
}

.si-verdict-cell[b-g2x2ti0nnm] {
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
    flex-wrap: wrap;
}

.si-why[b-g2x2ti0nnm] {
    color: var(--ft-text-muted);
    line-height: 1.45;
}

/* ── chips and pills ─────────────────────────────────────────────────────────────────────────── */

.si-chip[b-g2x2ti0nnm],
.si-pill[b-g2x2ti0nnm] {
    display: inline-block;
    padding: 0.125rem 0.5rem;
    border-radius: 999px;
    font-size: 0.75rem;
    font-weight: 600;
    white-space: nowrap;
    background: var(--ft-surface-2);
    color: var(--ft-text-muted);
}

.si-chip-vector[b-g2x2ti0nnm] { background: var(--ft-teal-bg);   color: var(--ft-teal-text); }
.si-chip-outline[b-g2x2ti0nnm]{ background: var(--ft-blue-bg);   color: var(--ft-blue-text); }
.si-chip-scan[b-g2x2ti0nnm]   { background: var(--ft-amber-bg);  color: var(--ft-amber-text); }
.si-chip-mixed[b-g2x2ti0nnm]  { background: var(--ft-purple-bg); color: var(--ft-purple-text); }

/* Deliberately neutral. See the header note: a refusal is the normal, correct answer here and a page of
   red would read as a page of errors about drawings that are perfectly fine. */
.si-pill-no[b-g2x2ti0nnm] {
    background: var(--ft-surface-2);
    color: var(--ft-text-muted);
}

.si-pill-good[b-g2x2ti0nnm] {
    background: var(--ft-green-bg);
    color: var(--ft-green-text);
}

@media (max-width: 900px) {
    /* The reason is prose; in a 120px column it is a stack of single words. Below this width the row
       becomes a block and each cell keeps its own line. */
    .si-table[b-g2x2ti0nnm] {
        grid-template-columns: 1fr;
    }

    .si-th[b-g2x2ti0nnm] {
        display: none;
    }

    .si-tr > *[b-g2x2ti0nnm] {
        border-bottom: none;
        padding: 0.125rem 0.75rem;
    }

    .si-tr > *:last-child[b-g2x2ti0nnm] {
        border-bottom: 1px solid var(--ft-border);
        padding-bottom: 0.75rem;
    }

    .si-num[b-g2x2ti0nnm] {
        padding-top: 0.75rem;
        font-size: 1rem;
    }
}
/* /Components/Pages/Estimates/SubcontractScopeCard.razor.rz.scp.css */
/* AB#1895 — the rail's subcontracted-scope card. Scoped: app.css is lane 0's. */

.sub-card[b-vx5i9r179v] {
    margin-top: .9rem;
    padding-top: .75rem;
    border-top: 1px solid var(--ft-border);
}

.sub-title[b-vx5i9r179v] {
    margin: 0 0 .4rem;
    font-size: .85rem;
    font-weight: 600;
}

.sub-text[b-vx5i9r179v] {
    margin: 0 0 .3rem;
    font-size: .84rem;
    line-height: 1.45;
}

.sub-why[b-vx5i9r179v],
.sub-muted[b-vx5i9r179v] {
    color: var(--ft-text-muted);
}

.sub-form[b-vx5i9r179v] {
    display: flex;
    flex-direction: column;
    gap: .45rem;
}

.sub-field[b-vx5i9r179v] {
    display: flex;
    flex-direction: column;
    gap: .2rem;
    font-size: .8rem;
}

.sub-check[b-vx5i9r179v] {
    font-size: .82rem;
}

.sub-actions[b-vx5i9r179v] {
    display: flex;
    flex-wrap: wrap;
    gap: .4rem;
    margin-top: .4rem;
}

.sub-error[b-vx5i9r179v] {
    margin-top: .5rem;
    padding: .5rem .7rem;
    border-radius: 8px;
    font-size: .82rem;
    background: var(--ft-amber-bg);
    color: var(--ft-amber-text);
}
/* /Components/Pages/Estimates/SubQuotes.razor.rz.scp.css */
/* AB#1641 — the sub-quotes page, as a LAYOUT. Its own file, like every estimating surface since AB#1732: app.css is the
   one stylesheet three lanes would all have to edit. Nothing here carries a claim a test has to see — the sentences, the
   figures and the links are all markup. */

.sq[b-wiil2xezcs] { max-width: none; }
.sq-pad[b-wiil2xezcs] { padding: 1rem 1.25rem; }
.sq-muted[b-wiil2xezcs] { color: var(--ft-text-muted); line-height: 1.55; }
.sq-small[b-wiil2xezcs] { font-size: .8rem; }

.sq-head[b-wiil2xezcs] { margin-bottom: 1rem; }
.sq-crumbs[b-wiil2xezcs] { display: flex; align-items: center; gap: .4rem; font-size: .8rem; color: var(--ft-text-faint); flex-wrap: wrap; }
.sq-h1[b-wiil2xezcs] { font-size: 1.35rem; font-weight: 700; margin: .4rem 0 .35rem; overflow-wrap: anywhere; }
.sq-number[b-wiil2xezcs] { font-variant-numeric: tabular-nums; }
.sq-dash[b-wiil2xezcs] { margin: 0 .4rem; color: var(--ft-text-faint); }
.sq-rev[b-wiil2xezcs] { margin-left: .5rem; font-size: .85rem; color: var(--ft-text-muted); font-weight: 600; }
.sq-intro[b-wiil2xezcs] { max-width: 70ch; margin: 0 0 .35rem; }
.sq-divisor[b-wiil2xezcs] { font-size: .85rem; font-weight: 600; margin: 0; }

.sq-note[b-wiil2xezcs], .sq-message[b-wiil2xezcs] { margin-bottom: 1rem; }
.sq-message.is-problem[b-wiil2xezcs] { border-left: 4px solid var(--ft-warning, #b45309); }
.sq-message.is-done[b-wiil2xezcs] { border-left: 4px solid var(--ft-primary, #2d6be4); }

.sq-partner[b-wiil2xezcs] { padding: 1rem 1.25rem; margin-bottom: 1rem; }
.sq-partner-head[b-wiil2xezcs] { margin-bottom: .5rem; }
.sq-h2[b-wiil2xezcs] { font-size: 1.1rem; font-weight: 700; margin: 0 0 .3rem; display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.sq-h3[b-wiil2xezcs] { font-size: .9rem; font-weight: 700; margin: 1rem 0 .4rem; }
.sq-inactive[b-wiil2xezcs] { opacity: .7; }
.sq-contacts[b-wiil2xezcs] { display: flex; flex-direction: column; gap: .1rem; font-size: .85rem; overflow-wrap: anywhere; }
.sq-lastquoted[b-wiil2xezcs] { margin: .3rem 0 0; font-size: .85rem; }

.sq-table-wrap[b-wiil2xezcs] { overflow-x: auto; }
.sq-table[b-wiil2xezcs] { width: 100%; }
.sq-table td[b-wiil2xezcs] { vertical-align: top; }
.sq-num[b-wiil2xezcs] { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
.sq-outstanding[b-wiil2xezcs] { color: var(--ft-warning, #b45309); font-weight: 600; font-size: .85rem; }
.sq-quoted[b-wiil2xezcs] { font-size: .85rem; font-weight: 600; }
.sq-price[b-wiil2xezcs] { display: flex; gap: .4rem; margin-top: .35rem; align-items: center; flex-wrap: wrap; }
.sq-quote-input[b-wiil2xezcs] { width: 9rem; max-width: 100%; }

.sq-docs[b-wiil2xezcs] { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .45rem; }
.sq-doc[b-wiil2xezcs] { padding: .45rem .6rem; border: 1px solid var(--ft-border, rgba(127,127,127,.25)); border-radius: 6px; }
.sq-doc.is-proposed[b-wiil2xezcs] { border-left: 4px solid var(--ft-primary, #2d6be4); }
.sq-doc-label[b-wiil2xezcs] { display: flex; gap: .5rem; align-items: flex-start; cursor: pointer; }
.sq-doc-name[b-wiil2xezcs] { font-weight: 600; overflow-wrap: anywhere; }
.sq-proposal[b-wiil2xezcs] { font-size: .82rem; margin: .2rem 0 0 1.6rem; overflow-wrap: anywhere; }

.sq-actions[b-wiil2xezcs] { display: flex; gap: .5rem; flex-wrap: wrap; margin-top: .8rem; }
.sq-sent[b-wiil2xezcs] { margin: .6rem 0 0; font-size: .85rem; }
.sq-unassigned[b-wiil2xezcs] { margin: .4rem 0 0; padding-left: 1.2rem; }
/* /Components/Pages/Integrations/ConnectionsTabs.razor.rz.scp.css */
.conn-tabs[b-8fjph9hyxg] {
    display: flex;
    gap: .25rem;
    border-bottom: 1px solid var(--ft-border);
    margin: 0 0 1.1rem;
}

.conn-tab[b-8fjph9hyxg] {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding: 0 .9rem;
    font-size: .9rem;
    font-weight: 600;
    color: var(--ft-text-muted);
    text-decoration: none;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
}

.conn-tab:hover[b-8fjph9hyxg] {
    color: var(--ft-navy);
}

.conn-tab.is-active[b-8fjph9hyxg] {
    color: var(--ft-navy);
    border-bottom-color: var(--ft-primary);
}
/* /Components/Pages/Integrations/PortalProfileReview.razor.rz.scp.css */
.review[b-nc4xtkgeyb] {
    max-width: 1100px;
}

.crumb[b-nc4xtkgeyb] {
    display: inline-block;
    margin: 0 0 .6rem;
    font-size: .85rem;
    text-decoration: none;
}

.review-head[b-nc4xtkgeyb] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .75rem;
}

.review-head h1[b-nc4xtkgeyb] {
    margin: 0;
    font-size: 1.4rem;
    font-weight: 700;
    color: var(--ft-navy);
}

.banner[b-nc4xtkgeyb] {
    margin: .9rem 0;
    padding: .85rem 1rem;
    border-radius: var(--ft-radius);
    font-size: .9rem;
    line-height: 1.5;
}

.banner p[b-nc4xtkgeyb] {
    margin: 0 0 .6rem;
}

.banner-amber[b-nc4xtkgeyb] {
    background: var(--ft-amber-bg);
    color: var(--ft-amber-text);
}

.banner-red[b-nc4xtkgeyb] {
    background: var(--ft-red-bg);
    color: var(--ft-red-text);
}

.review-grid[b-nc4xtkgeyb] {
    display: grid;
    grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr);
    gap: 1.25rem;
    align-items: start;
    margin-top: 1rem;
}

.review-main[b-nc4xtkgeyb],
.review-side[b-nc4xtkgeyb] {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

.review-card[b-nc4xtkgeyb] {
    padding: 1rem 1.1rem;
}

.review-card h2[b-nc4xtkgeyb] {
    margin: 0 0 .6rem;
    font-size: 1rem;
    font-weight: 600;
    color: var(--ft-navy);
}

.review-card h3[b-nc4xtkgeyb] {
    margin: .6rem 0 .35rem;
    font-size: .88rem;
    font-weight: 600;
}

.review-card p[b-nc4xtkgeyb] {
    margin: 0 0 .5rem;
    font-size: .9rem;
    line-height: 1.5;
}

.cov[b-nc4xtkgeyb] {
    border: 1px solid var(--ft-border);
    border-radius: var(--ft-radius);
    overflow: hidden;
}

.cov-row[b-nc4xtkgeyb] {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .75rem;
    padding: .6rem .8rem;
    border-top: 1px solid var(--ft-border-soft);
    font-size: .9rem;
}

.cov-row:first-child[b-nc4xtkgeyb] {
    border-top: none;
}

.cov-form[b-nc4xtkgeyb] {
    font-weight: 600;
    background: var(--ft-bg);
}

.cov-step[b-nc4xtkgeyb] {
    padding-left: 1.6rem;
}

.cov-other[b-nc4xtkgeyb] {
    color: var(--ft-text-muted);
    background: var(--ft-bg);
}

.chip[b-nc4xtkgeyb] {
    flex-shrink: 0;
    font-size: .75rem;
    padding: .15rem .5rem;
    border-radius: 999px;
}

.chip-seen[b-nc4xtkgeyb] {
    background: var(--ft-green-bg);
    color: var(--ft-green-text);
}

.chip-unverified[b-nc4xtkgeyb] {
    background: var(--ft-amber-bg);
    color: var(--ft-amber-text);
}

.chip-none[b-nc4xtkgeyb] {
    background: var(--ft-bg);
    color: var(--ft-text-muted);
    border: 1px solid var(--ft-border);
}

.review-does[b-nc4xtkgeyb] {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1rem;
}

.review-does h2[b-nc4xtkgeyb] {
    grid-column: 1 / -1;
}

.does-yes[b-nc4xtkgeyb] {
    color: var(--ft-green-text);
}

.does-no[b-nc4xtkgeyb] {
    color: var(--ft-red-text);
}

.history[b-nc4xtkgeyb] {
    list-style: none;
    margin: 0 0 .5rem;
    padding: 0;
}

.history li[b-nc4xtkgeyb] {
    display: grid;
    grid-template-columns: 11rem minmax(0, 1fr);
    gap: .75rem;
    padding: .5rem 0;
    border-top: 1px solid var(--ft-border-soft);
    font-size: .88rem;
}

.review-approve[b-nc4xtkgeyb] {
    border: 1px solid var(--ft-primary);
}

.review-revoke[b-nc4xtkgeyb] {
    border: 1px solid var(--ft-red);
}

.field[b-nc4xtkgeyb] {
    display: flex;
    flex-direction: column;
    gap: .25rem;
    margin: 0 0 .6rem;
    font-size: .85rem;
}

.field input[b-nc4xtkgeyb],
textarea[b-nc4xtkgeyb] {
    min-height: 40px;
    padding: .45rem .6rem;
    border: 1px solid var(--ft-border-strong);
    border-radius: var(--ft-radius-sm);
    font: inherit;
    font-size: .9rem;
}

textarea[b-nc4xtkgeyb] {
    width: 100%;
    box-sizing: border-box;
    resize: vertical;
}

.ack[b-nc4xtkgeyb] {
    display: flex;
    gap: .6rem;
    align-items: flex-start;
    margin: .6rem 0;
    font-size: .88rem;
    line-height: 1.5;
    cursor: pointer;
}

.ack input[b-nc4xtkgeyb] {
    width: 20px;
    height: 20px;
    margin-top: 2px;
    flex-shrink: 0;
}

.actions[b-nc4xtkgeyb] {
    display: flex;
    gap: .6rem;
    justify-content: flex-end;
    margin-top: .6rem;
}

.btn-danger[b-nc4xtkgeyb] {
    background: var(--ft-red);
    color: #fff;
}

.btn-danger-outline[b-nc4xtkgeyb] {
    border: 1px solid var(--ft-red);
    color: var(--ft-red-text);
}

.review-message[b-nc4xtkgeyb] {
    font-size: .9rem;
    margin: 0;
}

.review-message.ok[b-nc4xtkgeyb] {
    color: var(--ft-green-text);
}

.review-message.bad[b-nc4xtkgeyb] {
    color: var(--ft-red-text);
}

.state[b-nc4xtkgeyb] {
    display: inline-block;
    font-size: .8rem;
    font-weight: 600;
    padding: .25rem .6rem;
    border-radius: 999px;
    background: var(--ft-bg);
    color: var(--ft-text);
}

.state-approved[b-nc4xtkgeyb],
.state-nolongeroffered[b-nc4xtkgeyb] {
    background: var(--ft-green-bg);
    color: var(--ft-green-text);
}

.state-newversionwaiting[b-nc4xtkgeyb] {
    background: var(--ft-amber-bg);
    color: var(--ft-amber-text);
}

.state-revoked[b-nc4xtkgeyb] {
    background: var(--ft-red-bg);
    color: var(--ft-red-text);
}

.muted[b-nc4xtkgeyb] {
    color: var(--ft-text-muted);
}

.small[b-nc4xtkgeyb] {
    font-size: .82rem;
}

@media (max-width: 900px) {
    .review-grid[b-nc4xtkgeyb],
    .review-does[b-nc4xtkgeyb] {
        grid-template-columns: 1fr;
    }

    .history li[b-nc4xtkgeyb] {
        grid-template-columns: 1fr;
        gap: .15rem;
    }
}
/* /Components/Pages/Integrations/PortalProfiles.razor.rz.scp.css */
.portals[b-ne08onhni3] {
    max-width: 980px;
}

.portals-title[b-ne08onhni3] {
    margin: 0 0 .6rem;
    font-size: 1.4rem;
    font-weight: 700;
    color: var(--ft-navy);
}

.portals-intro[b-ne08onhni3] {
    margin: 0 0 .9rem;
    max-width: 760px;
    color: var(--ft-text-muted);
    font-size: .92rem;
    line-height: 1.55;
}

.portals-callout[b-ne08onhni3] {
    margin: 0 0 1.25rem;
    padding: .85rem 1rem;
    border-radius: var(--ft-radius);
    background: var(--ft-amber-bg);
    color: var(--ft-amber-text);
    font-size: .9rem;
    line-height: 1.5;
}

.portals-upgrade[b-ne08onhni3] {
    padding: 1rem;
    margin-bottom: 1rem;
    border-left: 3px solid var(--ft-primary);
}

.portals-upgrade p[b-ne08onhni3] {
    margin: 0 0 .6rem;
    font-size: .92rem;
}

.portals-section[b-ne08onhni3] {
    margin: 0 0 1.25rem;
}

.portals-section h2[b-ne08onhni3] {
    margin: 0 0 .6rem;
    font-size: 1rem;
    font-weight: 600;
    color: var(--ft-navy);
}

.portals-section h3[b-ne08onhni3] {
    margin: 1rem 0 .5rem;
    font-size: .92rem;
    font-weight: 600;
}

.portals-table[b-ne08onhni3] {
    border: 1px solid var(--ft-border);
    border-radius: var(--ft-radius-lg);
    background: var(--ft-surface);
    overflow: hidden;
}

.portals-row[b-ne08onhni3] {
    display: grid;
    grid-template-columns: minmax(0, 2.2fr) minmax(0, 2fr) minmax(0, 1.4fr) minmax(0, 1fr);
    gap: 1rem;
    padding: 1rem 1.1rem;
    align-items: center;
    border-top: 1px solid var(--ft-border-soft);
    font-size: .9rem;
}

.portals-head[b-ne08onhni3] {
    border-top: none;
    padding: .6rem 1.1rem;
    font-size: .74rem;
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--ft-text-muted);
}

.portals-name[b-ne08onhni3] {
    font-weight: 600;
    font-size: .95rem;
}

.portals-action[b-ne08onhni3] {
    display: flex;
    justify-content: flex-end;
}

.portals-byhand[b-ne08onhni3] {
    margin: .6rem 0 0;
    font-size: .88rem;
    color: var(--ft-text-muted);
}

.chips[b-ne08onhni3] {
    display: flex;
    flex-wrap: wrap;
    gap: .35rem;
    margin: .3rem 0;
}

.chip[b-ne08onhni3] {
    font-size: .75rem;
    padding: .15rem .5rem;
    border-radius: 999px;
}

.chip-seen[b-ne08onhni3] {
    background: var(--ft-green-bg);
    color: var(--ft-green-text);
}

.chip-unverified[b-ne08onhni3] {
    background: var(--ft-amber-bg);
    color: var(--ft-amber-text);
}

.state[b-ne08onhni3] {
    display: inline-block;
    font-size: .8rem;
    font-weight: 600;
    padding: .25rem .6rem;
    border-radius: 999px;
    background: var(--ft-bg);
    color: var(--ft-text);
}

.state-approved[b-ne08onhni3],
.state-nolongeroffered[b-ne08onhni3] {
    background: var(--ft-green-bg);
    color: var(--ft-green-text);
}

.state-newversionwaiting[b-ne08onhni3] {
    background: var(--ft-amber-bg);
    color: var(--ft-amber-text);
}

.state-revoked[b-ne08onhni3] {
    background: var(--ft-red-bg);
    color: var(--ft-red-text);
}

.portals-pair[b-ne08onhni3] {
    padding: 1rem 1.1rem;
}

.pair-code[b-ne08onhni3] {
    margin: .4rem 0 .2rem;
    font-family: ui-monospace, Menlo, Consolas, monospace;
    font-size: 1.6rem;
    font-weight: 700;
    letter-spacing: .12em;
}

.browsers[b-ne08onhni3] {
    list-style: none;
    margin: 0;
    padding: 0;
}

.browsers li[b-ne08onhni3] {
    display: flex;
    gap: 1rem;
    align-items: center;
    justify-content: space-between;
    padding: .6rem 0;
    border-top: 1px solid var(--ft-border-soft);
    font-size: .9rem;
}

.portals-message[b-ne08onhni3] {
    font-size: .9rem;
}

.muted[b-ne08onhni3] {
    color: var(--ft-text-muted);
}

.small[b-ne08onhni3] {
    font-size: .82rem;
}

.visually-hidden[b-ne08onhni3] {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
}

@media (max-width: 720px) {
    .portals-row[b-ne08onhni3] {
        grid-template-columns: 1fr;
        gap: .5rem;
    }

    .portals-head[b-ne08onhni3] {
        display: none;
    }

    .portals-action[b-ne08onhni3] {
        justify-content: flex-start;
    }
}
/* /Components/Pages/Jobs/JobEstimateCard.razor.rz.scp.css */
/* AB#2263 — the job page's "From the bid" card. Scoped; every token here is declared in both themes in app.css. */
.jec[b-typhffpsgd] { border-left: 3px solid var(--ft-accent); }

.jec-head[b-typhffpsgd] { display: flex; justify-content: space-between; align-items: center; gap: .75rem; }

.jec-number[b-typhffpsgd] {
    font-size: .75rem;
    font-weight: 700;
    font-family: ui-monospace, monospace;
    color: var(--ft-text-faint);
}

.jec-body[b-typhffpsgd] {
    padding: .75rem 1.25rem;
    font-size: .875rem;
    display: flex;
    flex-direction: column;
    gap: .6rem;
}

.jec-link[b-typhffpsgd] { color: var(--ft-accent); font-size: .82rem; align-self: flex-start; }

.jec-muted[b-typhffpsgd] { color: var(--ft-text-muted); font-size: .82rem; margin: 0; }

.jec-table[b-typhffpsgd] { width: 100%; border-collapse: collapse; table-layout: fixed; }

.jec-table th[b-typhffpsgd],
.jec-table td[b-typhffpsgd] {
    text-align: left;
    vertical-align: top;
    padding: .4rem .5rem .4rem 0;
    border-bottom: 1px solid var(--ft-border);
    overflow-wrap: anywhere;
}

.jec-table thead th[b-typhffpsgd] { font-size: .72rem; text-transform: uppercase; letter-spacing: .04em; color: var(--ft-text-faint); }

.jec-table tbody th[b-typhffpsgd] { font-weight: 600; color: var(--ft-text); width: 28%; }

.jec-fig[b-typhffpsgd] { display: block; font-weight: 700; color: var(--ft-text); }

.jec-src[b-typhffpsgd] { display: block; font-size: .72rem; color: var(--ft-text-muted); line-height: 1.35; }

.jec-people[b-typhffpsgd] { display: flex; flex-direction: column; gap: .2rem; padding-top: .3rem; }

.jec-people-head[b-typhffpsgd] { font-size: .72rem; text-transform: uppercase; letter-spacing: .04em; color: var(--ft-text-faint); }

.jec-role[b-typhffpsgd] { font-weight: 600; }

/* AB#2263 (Mark, 7 Oct): the awarded line and the bid line, stacked in one cell, each with its source under it. */
.jec-pair + .jec-pair[b-typhffpsgd] { margin-top: .5rem; }
/* /Components/Pages/Jobs/JobSiteView.razor.rz.scp.css */
/* AB#2233 — the single job-site view. Declared theme tokens only, no var(--ft-x, #hex) fallbacks (an undeclared token
   falls back to its light colour on a dark card). The model is SiteView3D's own markup and styles itself; the plan's
   canvas and overlay are this page's elements and drawing-viewer.js draws inside them. No app.css edit. */

.jsv[b-yhz3nv9xv7] {
    padding: 1.25rem 1.5rem;
    display: flex;
    flex-direction: column;
    gap: .9rem;
    min-width: 0;
}

.jsv-title[b-yhz3nv9xv7] {
    margin: 0;
}

.jsv-message[b-yhz3nv9xv7] {
    padding: 2rem;
    text-align: center;
    color: var(--ft-text-muted);
}

.jsv-muted[b-yhz3nv9xv7] {
    color: var(--ft-text-muted);
}

.jsv-h[b-yhz3nv9xv7] {
    font-size: .95rem;
    font-weight: 700;
    margin: 0 0 .5rem;
}

.jsv-h3[b-yhz3nv9xv7] {
    font-size: .82rem;
    font-weight: 700;
    margin: .9rem 0 .35rem;
    color: var(--ft-text-muted);
    text-transform: uppercase;
    letter-spacing: .03em;
}

/* ── header strip: sources first, then site type, the model's estimate, Refresh ─────────────────────────────────── */
.jsv-head[b-yhz3nv9xv7] {
    padding: .85rem 1rem;
    display: flex;
    flex-direction: column;
    gap: .45rem;
}

.jsv-head-row[b-yhz3nv9xv7] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .5rem 1.25rem;
    font-size: .85rem;
}

.jsv-sources[b-yhz3nv9xv7] {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .35rem;
}

.jsv-sources-label[b-yhz3nv9xv7] {
    font-weight: 700;
}

.jsv-chip[b-yhz3nv9xv7] {
    display: inline-flex;
    align-items: center;
    padding: .15rem .55rem;
    border-radius: 999px;
    border: 1px solid var(--ft-border);
    background: var(--ft-surface-2);
    font-size: .75rem;
    font-weight: 600;
}

.jsv-chip-plans[b-yhz3nv9xv7] {
    background: var(--ft-green-bg);
    color: var(--ft-green-text);
}

.jsv-chip-description[b-yhz3nv9xv7],
.jsv-chip-photos[b-yhz3nv9xv7] {
    background: var(--ft-blue-bg);
    color: var(--ft-blue-text);
}

.jsv-chip-template[b-yhz3nv9xv7] {
    background: var(--ft-amber-bg);
    color: var(--ft-amber-text);
}

.jsv-chip-pm_override[b-yhz3nv9xv7] {
    background: var(--ft-purple-bg);
    color: var(--ft-purple-text);
}

.jsv-refresh[b-yhz3nv9xv7] {
    margin-left: auto;
}

.jsv-refresh-outcome[b-yhz3nv9xv7] {
    margin: 0;
    font-size: .85rem;
}

.jsv-about[b-yhz3nv9xv7] {
    font-size: .8rem;
    color: var(--ft-text-muted);
}

.jsv-about ul[b-yhz3nv9xv7] {
    margin: .3rem 0 0;
    padding-left: 1.1rem;
}

/* ── banners and notes ─────────────────────────────────────────────────────────────────────────────────────────── */
.jsv-banner[b-yhz3nv9xv7] {
    display: flex;
    flex-wrap: wrap;
    gap: .35rem .75rem;
    align-items: baseline;
    padding: .65rem .9rem;
    border-radius: var(--ft-radius);
    border: 1px solid var(--ft-border);
    font-size: .85rem;
}

.jsv-banner-template[b-yhz3nv9xv7] {
    background: var(--ft-amber-bg);
    color: var(--ft-amber-text);
}

.jsv-banner-low[b-yhz3nv9xv7] {
    background: var(--ft-blue-bg);
    color: var(--ft-blue-text);
}

.jsv-notes ul[b-yhz3nv9xv7] {
    margin: 0;
    padding-left: 1.1rem;
    font-size: .85rem;
}

/* ── Plan | Model ──────────────────────────────────────────────────────────────────────────────────────────────── */
.jsv-views[b-yhz3nv9xv7] {
    display: inline-flex;
    align-self: flex-start;
    border: 1px solid var(--ft-border);
    border-radius: 8px;
    overflow: hidden;
}

.jsv-seg[b-yhz3nv9xv7] {
    padding: .35rem .9rem;
    font-size: .8rem;
    font-weight: 600;
    border: 0;
    background: transparent;
    color: var(--ft-text-muted);
    cursor: pointer;
}

.jsv-seg + .jsv-seg[b-yhz3nv9xv7] {
    border-left: 1px solid var(--ft-border);
}

.jsv-seg.on[b-yhz3nv9xv7] {
    background: var(--ft-accent);
    color: var(--ft-surface);
}

.jsv-seg:disabled[b-yhz3nv9xv7] {
    cursor: not-allowed;
    opacity: .5;
}

/* Plan | Model. Side by side only when the PANES have room for both, measured on the panes rather than the viewport:
   at a 1280 px window the panes are ~910 px wide (the sidebar and padding take the rest), and halving that left the
   model's canvas 174 px wide beside SiteView3D's own 17.5rem list — unusable (measured 7 Oct). So the rule is a
   container query: from 1100 px of pane width the plan sits beside the model; below it, Plan and Model are tabs. */
.jsv-panes[b-yhz3nv9xv7] {
    container-type: inline-size;
    min-width: 0;
}

.jsv-panes-grid[b-yhz3nv9xv7] {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 1rem;
    min-width: 0;
}

.jsv-pane[b-yhz3nv9xv7] {
    min-width: 0;
}

@container (min-width: 1100px) {
    .jsv-panes-grid[data-view="plan"][b-yhz3nv9xv7] {
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    }
}

@container (max-width: 1099.98px) {
    .jsv-panes-grid[data-view="plan"] .jsv-model[b-yhz3nv9xv7] {
        display: none;
    }
}

.jsv-plan[b-yhz3nv9xv7] {
    display: flex;
    flex-direction: column;
    gap: .5rem;
}

.jsv-plan-bar[b-yhz3nv9xv7] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: .5rem;
    font-size: .8rem;
}

.jsv-plan-bar select[b-yhz3nv9xv7] {
    margin-left: .35rem;
    max-width: 22rem;
}

.jsv-plan-pages[b-yhz3nv9xv7] {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
}

.jsv-icon[b-yhz3nv9xv7] {
    width: 1.8rem;
    height: 1.8rem;
    border: 1px solid var(--ft-border);
    border-radius: 6px;
    background: var(--ft-surface);
    color: var(--ft-text);
    cursor: pointer;
}

.jsv-icon:disabled[b-yhz3nv9xv7] {
    opacity: .45;
    cursor: not-allowed;
}

.jsv-plan-stage[b-yhz3nv9xv7] {
    position: relative;
    min-height: 360px;
    max-height: 72vh;
    overflow: auto;
    border: 1px solid var(--ft-border);
    border-radius: 8px;
    background: var(--ft-surface-2);
}

.jsv-plan-stage canvas[b-yhz3nv9xv7] {
    display: block;
    max-width: 100%;
    width: 100%;
}

.jsv-plan-overlay[b-yhz3nv9xv7] {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    pointer-events: none;
}

.jsv-plan-opening[b-yhz3nv9xv7] {
    position: absolute;
    top: .75rem;
    left: .75rem;
    font-size: .8rem;
}

/* ── the pin panel (M4: real data and links only) ──────────────────────────────────────────────────────────────── */
.jsv-panel[b-yhz3nv9xv7] {
    padding: .85rem 1rem;
}

.jsv-tabs[b-yhz3nv9xv7] {
    display: flex;
    flex-wrap: wrap;
    gap: .25rem;
    border-bottom: 1px solid var(--ft-border);
    margin-bottom: .6rem;
}

.jsv-tab[b-yhz3nv9xv7] {
    padding: .4rem .75rem;
    border: 0;
    border-bottom: 2px solid transparent;
    background: transparent;
    color: var(--ft-text-muted);
    font-size: .82rem;
    font-weight: 600;
    cursor: pointer;
}

.jsv-tab.on[b-yhz3nv9xv7] {
    color: var(--ft-text);
    border-bottom-color: var(--ft-accent);
}

.jsv-pins[b-yhz3nv9xv7],
.jsv-items[b-yhz3nv9xv7] {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: .35rem;
}

.jsv-pin[b-yhz3nv9xv7],
.jsv-items li[b-yhz3nv9xv7] {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: .25rem .75rem;
    padding: .4rem .55rem;
    border: 1px solid var(--ft-border-soft);
    border-radius: 6px;
    font-size: .83rem;
}

.jsv-pin.on[b-yhz3nv9xv7] {
    border-color: var(--ft-accent);
    background: var(--ft-surface-2);
}

.jsv-pin-name[b-yhz3nv9xv7] {
    border: 0;
    background: transparent;
    padding: 0;
    font-weight: 600;
    color: var(--ft-text);
    cursor: pointer;
    text-align: left;
}

.jsv-pin a[b-yhz3nv9xv7],
.jsv-items a[b-yhz3nv9xv7] {
    margin-left: auto;
    color: var(--ft-accent);
    font-weight: 600;
    text-decoration: none;
}

.jsv-joblevel-sentence[b-yhz3nv9xv7] {
    font-size: .83rem;
    margin: 0 0 .5rem;
}

.jsv-badges[b-yhz3nv9xv7] {
    display: flex;
    flex-wrap: wrap;
    gap: .35rem;
}

.jsv-badge[b-yhz3nv9xv7] {
    display: inline-flex;
    align-items: center;
    gap: .3rem;
    padding: .12rem .5rem;
    border-radius: 999px;
    border: 1px solid var(--ft-border);
    background: var(--ft-surface-2);
    color: var(--ft-text);
    font-size: .75rem;
    font-weight: 600;
    text-decoration: none;
}

.jsv-sev-critical[b-yhz3nv9xv7],
.jsv-sev-high[b-yhz3nv9xv7] {
    background: var(--ft-red-bg);
    color: var(--ft-red-text);
}

.jsv-sev-medium[b-yhz3nv9xv7] {
    background: var(--ft-amber-bg);
    color: var(--ft-amber-text);
}

/* AB#2234 — editing zones (managers) and the change history (every viewer). Declared tokens only. */
.jsv-edit-toggle[aria-pressed="true"][b-yhz3nv9xv7] {
    border-color: var(--ft-accent);
    color: var(--ft-accent);
}
.jsv-edit[b-yhz3nv9xv7] {
    margin-top: 1rem;
    padding: 1rem;
}
.jsv-edit > p[b-yhz3nv9xv7] {
    margin: 0 0 .4rem;
    font-size: .85rem;
}
.jsv-edit-grid[b-yhz3nv9xv7] {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 1rem;
    margin-top: .6rem;
}
@media (min-width: 900px) {
    .jsv-edit-grid[b-yhz3nv9xv7] {
        grid-template-columns: minmax(14rem, 1fr) minmax(18rem, 1.2fr);
    }
}
.jsv-edit-zones[b-yhz3nv9xv7] {
    list-style: none;
    margin: 0 0 .6rem;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: .3rem;
    max-height: 22rem;
    overflow-y: auto;
}
.jsv-edit-zone[b-yhz3nv9xv7] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .25rem .5rem;
    padding: .35rem .55rem;
    border: 1px solid var(--ft-border-soft);
    border-radius: 6px;
    font-size: .83rem;
}
.jsv-edit-zone.on[b-yhz3nv9xv7] {
    border-color: var(--ft-accent);
    background: var(--ft-surface-2);
}
.jsv-badge-team[b-yhz3nv9xv7] {
    background: var(--ft-purple-bg);
    color: var(--ft-purple-text);
}
.jsv-badge-kept[b-yhz3nv9xv7] {
    background: var(--ft-amber-bg);
    color: var(--ft-amber-text);
}
.jsv-edit-form[b-yhz3nv9xv7] {
    display: flex;
    flex-direction: column;
    gap: .55rem;
    padding: .75rem;
    border: 1px solid var(--ft-border);
    border-radius: var(--ft-radius);
    background: var(--ft-surface-2);
}
.jsv-field[b-yhz3nv9xv7] {
    display: flex;
    flex-direction: column;
    gap: .2rem;
    font-size: .8rem;
    color: var(--ft-text-muted);
}
.jsv-field input[b-yhz3nv9xv7],
.jsv-field select[b-yhz3nv9xv7] {
    font: inherit;
    font-size: .88rem;
    color: var(--ft-text);
    background: var(--ft-surface);
    border: 1px solid var(--ft-border);
    border-radius: 6px;
    padding: .3rem .45rem;
    min-width: 0;
}
.jsv-check[b-yhz3nv9xv7] {
    display: flex;
    align-items: center;
    gap: .45rem;
    font-size: .85rem;
}
.jsv-rect-row[b-yhz3nv9xv7] {
    display: flex;
    align-items: center;
    gap: .35rem;
}
.jsv-rect-row input[b-yhz3nv9xv7] {
    width: 7rem;
    text-align: right;
}
.jsv-edit-actions[b-yhz3nv9xv7] {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    margin-top: .25rem;
}
.jsv-edit-problems[b-yhz3nv9xv7] {
    margin: .75rem 0 0;
    padding: .5rem .75rem .5rem 1.6rem;
    border-radius: 6px;
    background: var(--ft-amber-bg);
    color: var(--ft-amber-text);
    font-size: .85rem;
}
.jsv-edit-status[b-yhz3nv9xv7] {
    margin: .75rem 0 0;
    font-weight: 600;
    font-size: .85rem;
}
.jsv-audit[b-yhz3nv9xv7] {
    margin-top: 1rem;
    padding: .75rem 1rem;
}
.jsv-audit summary[b-yhz3nv9xv7] {
    cursor: pointer;
    font-weight: 600;
}
.jsv-audit-entries[b-yhz3nv9xv7] {
    list-style: none;
    margin: .5rem 0 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: .5rem;
}
.jsv-audit-entries > li[b-yhz3nv9xv7] {
    padding: .4rem .55rem;
    border: 1px solid var(--ft-border-soft);
    border-radius: 6px;
    font-size: .83rem;
}
.jsv-audit-entries ul[b-yhz3nv9xv7] {
    margin: .2rem 0 0;
    padding-left: 1.1rem;
}

/* AB#2241 — the link to /help#site-view sits at the end of the header's first row. Refresh already takes the row's
   free space (margin-left: auto above), so when it is drawn the link simply follows it rather than splitting that space. */
.jsv-help[b-yhz3nv9xv7] { margin-left: auto; }
.jsv-refresh ~ .jsv-help[b-yhz3nv9xv7] { margin-left: 0; }
/* /Components/Pages/Operations/OverviewKpis.razor.rz.scp.css */
/* AB#2289 — the overview's KPI strip. Tiles size to their words in every language and never clip a label. */
.ok-strip[b-6yh0ptqga7] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
    gap: .75rem;
}

.ok-tile[b-6yh0ptqga7] {
    display: flex;
    flex-direction: column;
    gap: .25rem;
    padding: .85rem 1rem;
    border: 1px solid var(--ft-border);
    border-radius: 10px;
    background: var(--ft-surface);
    color: var(--ft-text);
    text-decoration: none;
    min-width: 0;
    transition: border-color .15s, background .15s;
}

.ok-tile:hover[b-6yh0ptqga7],
.ok-tile:focus-visible[b-6yh0ptqga7] {
    border-color: var(--ft-border-strong);
    background: var(--ft-surface-2);
}

.ok-tile:focus-visible[b-6yh0ptqga7] {
    outline: 2px solid var(--ft-border-strong);
    outline-offset: 2px;
}

.ok-value[b-6yh0ptqga7] {
    font-size: 1.6rem;
    font-weight: 800;
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
}

.ok-label[b-6yh0ptqga7] {
    font-size: .8rem;
    color: var(--ft-text-muted);
    line-height: 1.35;
    overflow-wrap: normal;
    word-break: normal;
    hyphens: auto;
}
/* /Components/Pages/Operations/SitesOverview.razor.rz.scp.css */
/* AB#2232 — the all-sites board. Scoped: every colour is a --ft-* token declared in BOTH themes (no var(--ft-x, #hex)
   fallback to an undeclared token — the --ft-success / --ft-danger trap).

   AB#2287 — THE BOARD FILLS THE PAGE. app.css lifts .ft-main-content's 1280 px cap for this page (.so-fullbleed), the
   root takes the viewport's height below the top bar, and .so-stagewrap is ONE grid. Mark's 13 Oct review of the first
   cut: cards floating OVER the scene hid a third of it and cut its labels, and the tools sat on a label. So the scene
   takes the middle of the grid and the cards sit AROUND it, never on it; the camera frames the sites in exactly the
   space the cards leave, and the tools have their own row:

        kpis   kpis    panel          the KPIs along the top, the panel (and the selected site's schedule) down the right,
        list   tools   panel          the Sites rail down the left (Mark, 13 Oct round 2: a slim rail by default, so the
                                      board is as big as it can be; opened, the full card pushes the board narrower),
        list   scene   panel          the scene's tools (and its honesty line) in their own row above the scene,
        list   today   panel          and today's schedule across every site under it (AB#2291).

   Below 1100 px (the drawer breakpoint) everything stacks, the scene first; the page asks for the 2D board on a phone. */

.so-root[b-7tcrzhuc7x] { display: flex; flex-direction: column; gap: 1rem; min-width: 0; }

/* 52px is .ft-topbar's height (app.css); 2.25rem is the vertical padding app.css gives .ft-main-content on this page. */
.so-fullbleed[b-7tcrzhuc7x] { height: max(40rem, calc(100dvh - 52px - 2.25rem)); gap: .75rem; }

.so-head[b-7tcrzhuc7x] {
    display: flex; align-items: flex-start; justify-content: space-between; flex-wrap: wrap; gap: .75rem;
}
.so-head .ft-page-title[b-7tcrzhuc7x] { margin-bottom: .1rem; }
.so-head .ft-page-subtitle[b-7tcrzhuc7x] { margin: 0; }
.so-head-tools[b-7tcrzhuc7x] { display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; font-size: .85rem; color: var(--ft-text-muted); }
.so-toggle[b-7tcrzhuc7x] { display: inline-flex; align-items: center; gap: .4rem; cursor: pointer; }
.so-updated[b-7tcrzhuc7x] { white-space: nowrap; }

/* ── the stage and its cards ───────────────────────────────────────────────────────────────────────────────────────── */

.so-stagewrap[b-7tcrzhuc7x] {
    position: relative;
    flex: 1 1 0;
    min-height: 0;
    display: grid;
    gap: .75rem;
    padding: .75rem;
    border-radius: var(--ft-radius-lg);
    border: 1px solid var(--ft-border);
    background: var(--ft-surface-2);
    overflow: hidden;
    isolation: isolate;
    grid-template-columns: auto minmax(0, 1fr) clamp(16rem, 21vw, 22rem);
    grid-template-rows: auto auto minmax(0, 1fr) auto;
    grid-template-areas:
        "kpis  kpis  panel"
        "list  tools panel"
        "list  scene panel"
        "list  today panel";
}

/* The scene: SiteView3D's stage (or its "cannot draw" sentence) in its own area, so nothing ever sits on it.
   !important on position: site-view-3d.js writes position: relative into the stage's own style attribute; the height
   comes from the grid area, not the 100% the page passes. */
.so-stagewrap[b-7tcrzhuc7x]  .sv3d-stage,
.so-stagewrap[b-7tcrzhuc7x]  .sv3d-unavailable {
    grid-area: scene;
    position: relative !important;
    width: 100%;
    height: auto !important;
    min-height: 16rem;
    border: 1px solid var(--ft-border);
    border-radius: var(--ft-radius-lg);
}

.so-stagewrap[b-7tcrzhuc7x]  .sv3d-toolbar { grid-area: tools; justify-self: center; align-self: end; }
/* The 2D fallback sentence is the one thing allowed on the scene: it only exists when the 3D view could not start. */
.so-stagewrap[b-7tcrzhuc7x]  .sv3d-fallback { grid-area: scene; z-index: 2; justify-self: center; align-self: start; max-width: 36rem; margin-top: .6rem; }

.so-card[b-7tcrzhuc7x] {
    position: relative;
    z-index: 2;
    min-width: 0;
    min-height: 0;
    padding: .65rem .8rem;
    border-radius: var(--ft-radius-lg);
    border: 1px solid var(--ft-border);
    background: var(--ft-surface);
    box-shadow: var(--ft-shadow-sm);
    overflow: auto;
}

.so-card-kpis[b-7tcrzhuc7x] { grid-area: kpis; align-self: start; }
.so-card-sites[b-7tcrzhuc7x] { grid-area: list; align-self: stretch; display: flex; flex-direction: column; gap: .55rem; width: clamp(14rem, 18vw, 19rem); }

/* The rail: the Sites card folded to an icon, its name and the issue counts. The board takes the rest of the width. */
.so-rail[b-7tcrzhuc7x] { grid-area: list; align-self: stretch; display: flex; position: relative; z-index: 2; }
.so-rail-btn[b-7tcrzhuc7x] {
    width: 4.25rem; display: flex; flex-direction: column; align-items: center; gap: .45rem; padding: .7rem .3rem;
    border-radius: var(--ft-radius-lg); border: 1px solid var(--ft-border); background: var(--ft-surface);
    box-shadow: var(--ft-shadow-sm); color: var(--ft-text); font: inherit; cursor: pointer;
}
.so-rail-btn:hover[b-7tcrzhuc7x], .so-rail-btn:focus-visible[b-7tcrzhuc7x] { border-color: var(--ft-border-strong); }
.so-rail-btn:focus-visible[b-7tcrzhuc7x] { outline: 2px solid var(--ft-accent); outline-offset: 2px; }
.so-rail-icon[b-7tcrzhuc7x] { width: 1.25rem; height: 1.25rem; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; }
.so-rail-label[b-7tcrzhuc7x] { font-size: .72rem; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--ft-text-muted); }
.so-rail-badge[b-7tcrzhuc7x] {
    min-width: 1.6rem; padding: .1rem .45rem; border-radius: 999px; font-size: .78rem; font-weight: 800; text-align: center;
    font-variant-numeric: tabular-nums;
}
.so-rail-failed[b-7tcrzhuc7x] { background: var(--ft-red-bg); color: var(--ft-red-text); }
.so-rail-amber[b-7tcrzhuc7x] { background: var(--ft-amber-bg); color: var(--ft-amber-text); }
.so-panel[b-7tcrzhuc7x] { grid-area: panel; align-self: start; max-height: 100%; }
.so-folded[b-7tcrzhuc7x] { align-self: start; }
/* The selected site's schedule, inside its panel. */
.so-lower[b-7tcrzhuc7x] { margin-top: 1rem; padding-top: .75rem; border-top: 1px solid var(--ft-border); }
.so-lower:not(.so-folded) > .so-card-h[b-7tcrzhuc7x] { margin-bottom: .5rem; }
.so-lower .so-timeline[b-7tcrzhuc7x] { flex-direction: column; overflow: visible; }
.so-lower .so-tl-item[b-7tcrzhuc7x] { max-width: none; min-width: 0; }

/* A card's heading is its fold: one button, the heading's words, a chevron that turns. */
.so-card-h[b-7tcrzhuc7x] { margin: 0; font-size: .8rem; font-weight: 700; color: var(--ft-text-muted); text-transform: uppercase; letter-spacing: .04em; }
.so-card:not(.so-folded) > .so-card-h[b-7tcrzhuc7x] { margin-bottom: .55rem; }
.so-card-toggle[b-7tcrzhuc7x] {
    width: 100%; display: flex; align-items: center; justify-content: space-between; gap: .5rem;
    padding: .1rem; border: 0; background: none; color: inherit; font: inherit; text-transform: inherit;
    letter-spacing: inherit; text-align: left; cursor: pointer;
}
.so-card-toggle:focus-visible[b-7tcrzhuc7x] { outline: 2px solid var(--ft-accent); outline-offset: 2px; border-radius: var(--ft-radius-sm); }
.so-card-toggle[b-7tcrzhuc7x]  .so-chevron {
    width: 1rem; height: 1rem; flex: none; fill: none; stroke: currentColor; stroke-width: 2; transition: transform .15s ease;
}
.so-folded .so-card-toggle[b-7tcrzhuc7x]  .so-chevron { transform: rotate(-90deg); }

/* The KPI strip, compact over the scene (AB#2289's own tiles, only tighter). */
.so-card-kpis[b-7tcrzhuc7x]  .ok-strip { grid-template-columns: none; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: .5rem; }
.so-card-kpis[b-7tcrzhuc7x]  .ok-tile { padding: .5rem .7rem; background: var(--ft-surface); }
.so-card-kpis[b-7tcrzhuc7x]  .ok-value { font-size: 1.3rem; }
.so-card-kpis[b-7tcrzhuc7x]  .ok-label { font-size: .75rem; }

/* The panel's heading is the selected site's name (or the invitation to pick one), in the panel's own voice. */
.so-panel .so-card-h[b-7tcrzhuc7x] { text-transform: none; letter-spacing: 0; }
.so-panel-name[b-7tcrzhuc7x] { font-size: 1.05rem; font-weight: 700; color: var(--ft-text); overflow-wrap: anywhere; }
.so-panel-empty[b-7tcrzhuc7x] { font-size: .88rem; font-weight: 400; color: var(--ft-text-muted); }

/* ── AB#2286: the first paint, in the board's own shape ────────────────────────────────────────────────────────────
   The scene area as a soft blurred placeholder (an abstract ground and five blocks, never anybody's data: nothing has
   been read yet), the KPI skeletons where the KPI card floats, a spinner and one sentence in the middle. */
.so-loading[b-7tcrzhuc7x] { grid-template-rows: auto minmax(0, 1fr); }
.so-skel-kpis[b-7tcrzhuc7x] { grid-area: kpis; align-self: start; display: grid; grid-template-columns: repeat(auto-fit, minmax(9.5rem, 1fr)); gap: .5rem; }
.so-skel-tile[b-7tcrzhuc7x] {
    min-height: 3.9rem; display: flex; flex-direction: column; justify-content: center; gap: .45rem; padding: .55rem .75rem;
    border-radius: 10px; border: 1px solid var(--ft-border); background: var(--ft-surface);
}
.so-skel-tile span[b-7tcrzhuc7x] { display: block; height: .75rem; width: 55%; border-radius: 6px; background: var(--ft-surface-2); }
.so-skel-tile span:first-child[b-7tcrzhuc7x] { height: 1.3rem; width: 35%; }
.so-skel-scene[b-7tcrzhuc7x] {
    position: absolute; inset: -24px; z-index: 0; filter: blur(14px); opacity: .85;
    background:
        radial-gradient(60% 50% at 45% 55%, var(--ft-surface-3) 0%, transparent 70%),
        linear-gradient(180deg, var(--ft-surface) 0%, var(--ft-surface-2) 100%);
}
.so-skel-scene i[b-7tcrzhuc7x] {
    position: absolute; bottom: 30%; width: 9%; border-radius: 6px;
    background: var(--ft-border-strong); opacity: .55;
}
.so-skel-scene i:nth-child(1)[b-7tcrzhuc7x] { left: 14%; height: 22%; }
.so-skel-scene i:nth-child(2)[b-7tcrzhuc7x] { left: 30%; height: 34%; }
.so-skel-scene i:nth-child(3)[b-7tcrzhuc7x] { left: 46%; height: 18%; background: var(--ft-primary); opacity: .35; }
.so-skel-scene i:nth-child(4)[b-7tcrzhuc7x] { left: 62%; height: 28%; }
.so-skel-scene i:nth-child(5)[b-7tcrzhuc7x] { left: 78%; height: 14%; }
.so-skel-status[b-7tcrzhuc7x] {
    position: absolute; inset: 0; z-index: 1; display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: .75rem; color: var(--ft-text-muted); font-weight: 600; font-size: .92rem; text-align: center; padding: 1rem;
}
.so-spinner[b-7tcrzhuc7x] {
    width: 2.25rem; height: 2.25rem; border-radius: 50%;
    border: 3px solid var(--ft-border); border-top-color: var(--ft-primary);
    animation: so-spin-b-7tcrzhuc7x .9s linear infinite;
}
@keyframes so-spin-b-7tcrzhuc7x { to { transform: rotate(360deg); } }
/* Reduced motion: the spinner stands still (a ring with its accent arc) and the sentence still says what is happening. */
@media (prefers-reduced-motion: reduce) {
    .so-spinner[b-7tcrzhuc7x] { animation: none; }
    .so-card-toggle[b-7tcrzhuc7x]  .so-chevron { transition: none; }
}

/* ── below the drawer breakpoint: the scene first, the cards stacked under it ─────────────────────────────────────── */
@media (max-width: 1100px) {
    .so-fullbleed[b-7tcrzhuc7x] { height: auto; }
    .so-stagewrap[b-7tcrzhuc7x] {
        flex: none;
        min-height: 0;
        padding: 0;
        border: 0;
        background: none;
        overflow: visible;
        grid-template-columns: minmax(0, 1fr);
        grid-template-rows: none;
        grid-template-areas: "tools" "scene" "today" "kpis" "panel" "list";
    }
    .so-stagewrap[b-7tcrzhuc7x]  .sv3d-stage,
    .so-stagewrap[b-7tcrzhuc7x]  .sv3d-unavailable {
        grid-area: scene;
        position: relative !important;
        width: 100%;
        height: 58vh !important;
        min-height: 20rem;
        border: 1px solid var(--ft-border);
        border-radius: var(--ft-radius-lg);
    }
    .so-stagewrap[b-7tcrzhuc7x]  .sv3d-toolbar { justify-self: stretch; }
    .so-card[b-7tcrzhuc7x] { align-self: stretch; max-height: none; }
    .so-card-sites[b-7tcrzhuc7x] { width: auto; }
    .so-rail-btn[b-7tcrzhuc7x] { width: 100%; flex-direction: row; justify-content: flex-start; padding: .55rem .8rem; }
    .so-card-sites[b-7tcrzhuc7x] { max-height: 32rem; }
    .so-card-kpis[b-7tcrzhuc7x]  .ok-strip { grid-auto-flow: row; grid-template-columns: repeat(auto-fit, minmax(8.5rem, 1fr)); }
    .so-loading[b-7tcrzhuc7x] { padding: 0; min-height: 26rem; border: 1px solid var(--ft-border); background: var(--ft-surface-2); overflow: hidden; }
    .so-loading .so-skel-kpis[b-7tcrzhuc7x] { margin: .75rem; }
}

/* ── the cards' contents ────────────────────────────────────────────────────────────────────────────────────────────── */

.so-search .ft-input[b-7tcrzhuc7x] { width: 100%; }
.so-sr[b-7tcrzhuc7x] {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden;
    clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

/* The legend is the list's filter: one chip per tier, pressed = shown. */
.so-legend[b-7tcrzhuc7x] { display: flex; flex-wrap: wrap; gap: .35rem; list-style: none; margin: 0; padding: 0; font-size: .78rem; }
.so-legend li[b-7tcrzhuc7x] { display: inline-flex; }
.so-chip[b-7tcrzhuc7x] {
    display: inline-flex; align-items: center; gap: .35rem; padding: .2rem .55rem; border-radius: 999px;
    border: 1px solid var(--ft-border); background: var(--ft-surface-2); color: var(--ft-text-muted); font: inherit; cursor: pointer;
}
.so-chip.on[b-7tcrzhuc7x] { background: var(--ft-surface); color: var(--ft-text); border-color: var(--ft-border-strong); font-weight: 600; }
.so-chip:not(.on) .so-dot[b-7tcrzhuc7x] { opacity: .35; }
.so-chip:focus-visible[b-7tcrzhuc7x] { outline: 2px solid var(--ft-accent); outline-offset: 2px; }
.so-only[b-7tcrzhuc7x] { display: inline-flex; align-items: center; gap: .45rem; font-size: .82rem; color: var(--ft-text); cursor: pointer; }

.so-dot[b-7tcrzhuc7x] { display: inline-block; width: .7rem; height: .7rem; border-radius: 50%; flex: 0 0 auto; }
.so-dot-failed[b-7tcrzhuc7x] { background: var(--ft-red); }
.so-dot-amber[b-7tcrzhuc7x] { background: var(--ft-amber); }
.so-dot-clear[b-7tcrzhuc7x] { background: var(--ft-green); }

.so-h[b-7tcrzhuc7x] { font-size: .95rem; font-weight: 700; color: var(--ft-text); margin: 0 0 .5rem; }
.so-muted[b-7tcrzhuc7x] { color: var(--ft-text-muted); font-size: .88rem; margin: 0; }

.so-site-list[b-7tcrzhuc7x] { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .35rem; }
.so-site-item[b-7tcrzhuc7x] {
    display: flex; gap: .55rem; align-items: flex-start; width: 100%; text-align: left;
    padding: .45rem .6rem; border-radius: 8px; border: 1px solid var(--ft-border);
    background: var(--ft-surface); color: var(--ft-text); cursor: pointer; font: inherit;
}
.so-site-item:hover[b-7tcrzhuc7x], .so-site-item:focus-visible[b-7tcrzhuc7x] { border-color: var(--ft-border-strong); }
.so-site-item b[b-7tcrzhuc7x] { font-size: .86rem; font-weight: 600; line-height: 1.35; }
.so-site-item .so-dot[b-7tcrzhuc7x] { margin-top: .3rem; }
.so-site-item small[b-7tcrzhuc7x] { display: block; color: var(--ft-text-muted); font-size: .78rem; line-height: 1.4; }
.so-tier-failed.so-site-item[b-7tcrzhuc7x] { border-left: 3px solid var(--ft-red); }
.so-tier-amber.so-site-item[b-7tcrzhuc7x] { border-left: 3px solid var(--ft-amber); }
.so-tier-clear.so-site-item[b-7tcrzhuc7x] { border-left: 3px solid var(--ft-green); }
.so-site-item.on[b-7tcrzhuc7x] { border-color: var(--ft-primary); box-shadow: 0 0 0 1px var(--ft-primary); }
.so-site-item .so-site-trip[b-7tcrzhuc7x] { color: var(--ft-accent); font-weight: 600; }

.so-panel-status[b-7tcrzhuc7x] { display: flex; gap: .45rem; align-items: flex-start; font-size: .84rem; margin: 0 0 .5rem; color: var(--ft-text-muted); }
.so-panel-status .so-dot[b-7tcrzhuc7x] { margin-top: .28rem; }
.so-panel-status.so-tier-failed[b-7tcrzhuc7x] { color: var(--ft-red-text); }
.so-panel-status.so-tier-amber[b-7tcrzhuc7x] { color: var(--ft-amber-text); }

.so-facts[b-7tcrzhuc7x] { margin: 0; display: grid; gap: .2rem; font-size: .86rem; }
.so-facts dt[b-7tcrzhuc7x] { font-weight: 600; color: var(--ft-text-muted); font-size: .76rem; text-transform: uppercase; letter-spacing: .03em; margin-top: .45rem; }
.so-facts dd[b-7tcrzhuc7x] { margin: 0; color: var(--ft-text); overflow-wrap: anywhere; }

.so-lines[b-7tcrzhuc7x] { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .15rem; }
.so-red[b-7tcrzhuc7x] { color: var(--ft-red-text); font-weight: 600; }

.so-badges[b-7tcrzhuc7x] { display: flex; flex-wrap: wrap; gap: .3rem; }
.so-badge[b-7tcrzhuc7x] {
    display: inline-block; font-size: .76rem; padding: .1rem .5rem; border-radius: 999px;
    background: var(--ft-surface-2); color: var(--ft-text-muted);
}
.so-badge-red[b-7tcrzhuc7x] { background: var(--ft-red-bg); color: var(--ft-red-text); }

.so-trip[b-7tcrzhuc7x] { color: var(--ft-text-muted); font-size: .8rem; margin-top: .2rem; }

.so-actions[b-7tcrzhuc7x] { display: flex; flex-wrap: wrap; gap: .4rem; margin-top: .9rem; }

.so-timeline[b-7tcrzhuc7x] { list-style: none; margin: 0 0 .75rem; padding: 0; display: flex; gap: .5rem; overflow-x: auto; }
.so-tl-item[b-7tcrzhuc7x] {
    flex: 0 0 auto; min-width: 11rem; max-width: 16rem; padding: .45rem .6rem; border-radius: 8px;
    border: 1px solid var(--ft-border-soft); background: var(--ft-surface);
    display: flex; flex-direction: column; gap: .15rem; font-size: .8rem;
}
.so-tl-when[b-7tcrzhuc7x] { color: var(--ft-text-muted); }
.so-tl-what[b-7tcrzhuc7x] { color: var(--ft-text); font-weight: 600; overflow-wrap: anywhere; }
.so-tl-status[b-7tcrzhuc7x] { color: var(--ft-text-muted); font-size: .75rem; }

.so-tabs[b-7tcrzhuc7x] { display: flex; gap: .25rem; border-bottom: 1px solid var(--ft-border); margin-bottom: .6rem; }
.so-tab[b-7tcrzhuc7x] {
    border: none; background: transparent; padding: .4rem .7rem; cursor: pointer; font: inherit; font-size: .85rem;
    color: var(--ft-text-muted); border-bottom: 2px solid transparent; margin-bottom: -1px;
}
.so-tab.on[b-7tcrzhuc7x] { color: var(--ft-text); border-bottom-color: var(--ft-primary); font-weight: 600; }
.so-rows[b-7tcrzhuc7x] { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .3rem; font-size: .86rem; }
.so-rows small[b-7tcrzhuc7x] { color: var(--ft-text-muted); margin-left: .35rem; }
.so-rows a[b-7tcrzhuc7x] { color: var(--ft-primary); }

/* ── AB#2290: the panel with nothing selected — how today stands ──────────────────────────────────────────────────── */
.so-summary[b-7tcrzhuc7x] { display: flex; flex-direction: column; gap: .6rem; }
.so-summary-figures[b-7tcrzhuc7x] { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .5rem; margin: 0; }
.so-summary-figures > div[b-7tcrzhuc7x] {
    padding: .5rem .65rem; border-radius: 10px; border: 1px solid var(--ft-border); background: var(--ft-surface);
    display: flex; flex-direction: column-reverse; gap: .15rem;
}
.so-summary-figures dt[b-7tcrzhuc7x] { font-size: .74rem; font-weight: 500; color: var(--ft-text-muted); line-height: 1.3; }
.so-summary-figures dd[b-7tcrzhuc7x] { margin: 0; font-size: 1.3rem; font-weight: 800; color: var(--ft-text); font-variant-numeric: tabular-nums; }
.so-summary-h[b-7tcrzhuc7x] { margin: .2rem 0 0; font-size: .74rem; font-weight: 700; color: var(--ft-text-muted); text-transform: uppercase; letter-spacing: .04em; }
.so-summary-list[b-7tcrzhuc7x] { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .3rem; }
.so-summary-item[b-7tcrzhuc7x] {
    display: flex; gap: .5rem; align-items: flex-start; width: 100%; text-align: left; padding: .4rem .55rem;
    border-radius: 8px; border: 1px solid var(--ft-border); background: var(--ft-surface); color: var(--ft-text);
    cursor: pointer; font: inherit;
}
.so-summary-item:hover[b-7tcrzhuc7x], .so-summary-item:focus-visible[b-7tcrzhuc7x] { border-color: var(--ft-border-strong); }
.so-summary-item .so-dot[b-7tcrzhuc7x] { margin-top: .3rem; }
.so-summary-item b[b-7tcrzhuc7x] { display: block; font-size: .84rem; font-weight: 600; }
.so-summary-item small[b-7tcrzhuc7x] { display: block; color: var(--ft-text-muted); font-size: .76rem; line-height: 1.35; }
.so-summary-hint[b-7tcrzhuc7x] { font-size: .8rem; }
.so-summary .so-actions[b-7tcrzhuc7x] { margin-top: 0; }
.so-panel-back[b-7tcrzhuc7x] {
    display: inline-flex; align-items: center; gap: .3rem; margin: 0 0 .5rem; padding: .15rem .4rem .15rem .15rem;
    border: 0; border-radius: var(--ft-radius-sm); background: none; color: var(--ft-primary); font: inherit;
    font-size: .8rem; font-weight: 600; cursor: pointer;
}
.so-panel-back:hover[b-7tcrzhuc7x], .so-panel-back:focus-visible[b-7tcrzhuc7x] { background: var(--ft-surface-2); }
.so-panel-back svg[b-7tcrzhuc7x] { width: .9rem; height: .9rem; fill: none; stroke: currentColor; stroke-width: 2.2; }

/* ── AB#2291: today's schedule across every site, under the scene ─────────────────────────────────────────────────── */
.so-today[b-7tcrzhuc7x] { grid-area: today; align-self: end; padding: .55rem .7rem; }
.so-today:not(.so-folded) > .so-card-h[b-7tcrzhuc7x] { margin-bottom: .45rem; }
.so-today-list[b-7tcrzhuc7x] { list-style: none; margin: 0; padding: 0 0 .15rem; display: flex; gap: .45rem; overflow-x: auto; }
.so-today-item[b-7tcrzhuc7x] {
    flex: 0 0 auto; display: grid; grid-template-columns: auto 1fr; column-gap: .5rem; row-gap: .05rem; align-items: baseline;
    min-width: 11rem; max-width: 16rem; padding: .4rem .6rem; border-radius: 8px; border: 1px solid var(--ft-border);
    background: var(--ft-surface-2); color: var(--ft-text); font: inherit; text-align: left; cursor: pointer;
}
.so-today-item:hover[b-7tcrzhuc7x], .so-today-item:focus-visible[b-7tcrzhuc7x] { border-color: var(--ft-border-strong); }
.so-today-item.on[b-7tcrzhuc7x] { border-color: var(--ft-primary); box-shadow: 0 0 0 1px var(--ft-primary); }
.so-today-time[b-7tcrzhuc7x] { grid-row: span 2; font-weight: 800; font-variant-numeric: tabular-nums; font-size: .9rem; }
.so-today-site[b-7tcrzhuc7x] { font-weight: 600; font-size: .82rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.so-today-crew[b-7tcrzhuc7x] { color: var(--ft-text-muted); font-size: .74rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* /Components/Pages/PriceBooks/PriceBookItemEdit.razor.rz.scp.css */
/* ═══════════════════════════════════════════════════════════════════════════════════════════════
   Editing one catalogue row, bands and all (AB#1743).

   Its own file, like every surface since AB#1732: app.css is the one file three lanes would all have to
   edit to do UI at once, and a merge there breaks pages nobody touched. Nothing here needs app.css — if
   it ever does, that is a join and it goes to lane 0 rather than into the shared sheet.

   Colours are tokens, never literals. A hard-coded hex looks right in the screenshot and wrong at night.
   ═══════════════════════════════════════════════════════════════════════════════════════════════ */

.wrap[b-9b5hq6a45u] {
    max-width: 820px;
    padding: 0 .25rem;
}

.crumb[b-9b5hq6a45u] {
    font-size: .85rem;
    color: var(--ft-text-muted);
    text-decoration: none;
}

.crumb:hover[b-9b5hq6a45u] { color: var(--ft-text); }

.muted[b-9b5hq6a45u] { color: var(--ft-text-muted); }

.card[b-9b5hq6a45u] {
    padding: 1rem;
    margin-bottom: 1rem;
}

.section[b-9b5hq6a45u] {
    margin: 0 0 .3rem;
    font-size: 1rem;
    font-weight: 650;
    color: var(--ft-navy);
}

.hint[b-9b5hq6a45u] {
    margin: 0 0 .25rem;
    color: var(--ft-text-muted);
    font-size: .88rem;
    line-height: 1.5;
}

/* ── the row's identity ────────────────────────────────────────────────────────────────────────
   The code reads as data, not as a heading: it is a SKU the customer typed into their own system and
   the monospace is what makes "0" and "O" distinguishable in it. */
.identity[b-9b5hq6a45u] {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
}

.code[b-9b5hq6a45u] {
    font-family: var(--ft-mono, monospace);
    font-size: 1rem;
    font-weight: 600;
    color: var(--ft-navy);
}

.book[b-9b5hq6a45u] {
    font-size: .85rem;
    color: var(--ft-text-muted);
}

/* Two columns where the fields are genuinely a pair — price beside cost, category beside supplier —
   and one column on a phone, where side-by-side money boxes are how a rate gets typed into the wrong
   one. */
.grid[b-9b5hq6a45u] {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0 1rem;
}

@media (max-width: 640px) {
    .grid[b-9b5hq6a45u] { grid-template-columns: 1fr; }
}

/* ── the band table ────────────────────────────────────────────────────────────────────────────
   Scrolls inside itself rather than pushing the page sideways: four columns of number boxes is wider
   than a phone, and a horizontally scrolling PAGE loses the Save button off the right edge. */
.bandtable[b-9b5hq6a45u] {
    overflow-x: auto;
    margin-bottom: .5rem;
}

.bandtable table[b-9b5hq6a45u] { width: 100%; }

.num[b-9b5hq6a45u] {
    text-align: right;
    min-width: 6rem;
    font-family: var(--ft-mono, monospace);
    font-size: .88rem;
}

.rowaction[b-9b5hq6a45u] { white-space: nowrap; }

.small[b-9b5hq6a45u] {
    font-size: .8rem;
    padding: .3rem .7rem;
}

.actions[b-9b5hq6a45u] {
    display: flex;
    gap: .6rem;
    align-items: center;
    flex-wrap: wrap;
    margin-top: .25rem;
}
/* /Components/Pages/PriceBooks/PriceBookLowConfidenceRates.razor.rz.scp.css */
/* AB#2478 — the price book's low-confidence block and its wide-range callout. */
.pb-lowconf[b-t039e5r7gd] {
    padding: 1rem;
    margin-top: 1rem;
    border-left: 3px solid var(--ft-amber);
}

.pb-lowconf-wide[b-t039e5r7gd] {
    border-left-color: var(--ft-red);
}

.pb-lowconf-title[b-t039e5r7gd] {
    margin: 0 0 .4rem;
    font-size: 1rem;
    font-weight: 650;
    color: var(--ft-navy);
}

.pb-lowconf-intro[b-t039e5r7gd] {
    margin: 0 0 .6rem;
    color: var(--ft-text-muted);
    font-size: .85rem;
    line-height: 1.5;
}

.pb-lowconf-list[b-t039e5r7gd] {
    margin: 0;
    padding-left: 1.1rem;
    display: grid;
    gap: .35rem;
}

.pb-lowconf-name[b-t039e5r7gd] {
    font-weight: 600;
    margin-right: .5rem;
}

.pb-lowconf-figures[b-t039e5r7gd] {
    color: var(--ft-text-muted);
    font-size: .85rem;
    white-space: normal;
}
/* /Components/Pages/Settings/ApprovalChainSettings.razor.rz.scp.css */
/* AB#1876 — the approval chain editor. Scoped: nothing here reaches another page, and app.css is lane 0's. */

.ac-page[b-ohhjw3geyr] {
    max-width: 760px;
}

.ac-crumb[b-ohhjw3geyr] {
    display: inline-block;
    font-size: .85rem;
    margin-bottom: .5rem;
}

.ac-none[b-ohhjw3geyr] {
    padding: .7rem .9rem;
    border-radius: 8px;
    background: var(--ft-surface-2);
    color: var(--ft-text-muted);
    margin-bottom: .75rem;
}

.ac-steps[b-ohhjw3geyr] {
    list-style: none;
    margin: 0 0 .75rem;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: .75rem;
}

.ac-step[b-ohhjw3geyr] {
    padding: .9rem 1rem;
    display: flex;
    flex-direction: column;
    gap: .35rem;
}

.ac-step-head[b-ohhjw3geyr] {
    display: flex;
    justify-content: space-between;
    align-items: center;
    flex-wrap: wrap;
    gap: .5rem;
    margin-bottom: .25rem;
}

.ac-step-number[b-ohhjw3geyr] {
    font-size: .8rem;
    font-weight: 650;
    text-transform: uppercase;
    letter-spacing: .03em;
    color: var(--ft-text-muted);
}

.ac-step-tools[b-ohhjw3geyr] {
    display: flex;
    gap: .35rem;
    flex-wrap: wrap;
}

.ac-approvers-label[b-ohhjw3geyr] {
    margin-top: .5rem;
}

.ac-people[b-ohhjw3geyr] {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: .4rem;
}

.ac-person[b-ohhjw3geyr] {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    padding: .25rem .35rem .25rem .7rem;
    border-radius: 999px;
    background: var(--ft-surface-2);
    font-size: .88rem;
}

.ac-person[data-standing="Inactive"][b-ohhjw3geyr],
.ac-person[data-standing="RoleCannotApprove"][b-ohhjw3geyr],
.ac-person[data-standing="NotInOrg"][b-ohhjw3geyr] {
    background: var(--ft-red-bg);
    color: var(--ft-red-text);
}

.ac-badge[b-ohhjw3geyr] {
    font-size: .72rem;
    font-weight: 600;
}

.ac-remove[b-ohhjw3geyr] {
    border: 0;
    background: transparent;
    color: inherit;
    cursor: pointer;
    font-size: 1rem;
    line-height: 1;
    padding: 0 .3rem;
}

.ac-add[b-ohhjw3geyr] {
    max-width: 18rem;
    margin-top: .35rem;
}

.ac-row[b-ohhjw3geyr] {
    display: flex;
    align-items: center;
    gap: .75rem;
    flex-wrap: wrap;
    margin: .75rem 0;
}

.ac-onbehalf[b-ohhjw3geyr] {
    margin: 1rem 0 .5rem;
}

.ac-check[b-ohhjw3geyr] {
    display: flex;
    align-items: center;
    gap: .5rem;
    font-size: .92rem;
}

.ac-muted[b-ohhjw3geyr] {
    color: var(--ft-text-muted);
    font-size: .85rem;
}

.ac-errors[b-ohhjw3geyr] {
    padding: .85rem 1rem;
    border-left: 3px solid var(--ft-red-text);
    background: var(--ft-surface);
    font-size: .88rem;
    margin: .75rem 0;
}

.ac-errors ul[b-ohhjw3geyr] {
    margin: 0;
    padding-left: 1.1rem;
}

.ac-saved[b-ohhjw3geyr] {
    color: var(--ft-green-text);
    font-size: .88rem;
}
/* /Components/Pages/Settings/CaptureNoticeSettings.razor.rz.scp.css */
/* AB#41 — the capture notice. Scoped: app.css is lane 0's. Declared theme tokens, or a fixed hue mixed INTO
   --ft-surface so it reads on both themes (batch AG). */

.cn-page[b-hioyx26r7g] { max-width: 760px; }

.cn-muted[b-hioyx26r7g] { color: var(--ft-text-muted); font-size: .85rem; }

.cn-card[b-hioyx26r7g] { padding: 1.1rem 1.25rem; display: flex; flex-direction: column; gap: .85rem; }

.cn-statement[b-hioyx26r7g] {
    margin: 0;
    padding: .75rem 1rem;
    border-left: 3px solid var(--ft-navy);
    background: color-mix(in srgb, #1e3a5f 6%, var(--ft-surface));
    color: var(--ft-text);
    font-size: .95rem;
}

.cn-ok[b-hioyx26r7g] {
    margin: 0;
    padding: .6rem .85rem;
    border-radius: 8px;
    background: color-mix(in srgb, #059669 10%, var(--ft-surface));
    color: var(--ft-text);
    font-size: .88rem;
}

.cn-warn[b-hioyx26r7g] {
    margin: 0;
    padding: .6rem .85rem;
    border-radius: 8px;
    background: color-mix(in srgb, #d97706 10%, var(--ft-surface));
    color: var(--ft-text);
    font-size: .88rem;
}

.cn-error[b-hioyx26r7g] {
    background: color-mix(in srgb, #b42318 8%, var(--ft-surface));
    border: 1px solid color-mix(in srgb, #b42318 30%, transparent);
    color: var(--ft-text);
    padding: .65rem .9rem;
    border-radius: 8px;
}

.cn-card button[b-hioyx26r7g] { align-self: flex-start; }
/* /Components/Pages/Settings/CompanyProfile.razor.rz.scp.css */
/* AB#1397 — the read-only company profile. Scoped: nothing here reaches another page, and app.css is lane 0's.
   Colours are the declared theme tokens, or a fixed hue mixed INTO --ft-surface so a chip reads on both themes
   (batch AG: an undeclared --ft-* token silently falls back to its light-theme hex on a dark card). */

.cp-page[b-waa0cxuadw] { max-width: 1100px; }

.cp-muted[b-waa0cxuadw] { color: var(--ft-text-muted); }

.cp-error[b-waa0cxuadw] {
    background: color-mix(in srgb, #b42318 8%, var(--ft-surface));
    border: 1px solid color-mix(in srgb, #b42318 30%, transparent);
    color: var(--ft-text); padding: .65rem .9rem; border-radius: 8px;
}

.cp-readonly[b-waa0cxuadw] { font-size: .82rem; color: var(--ft-text-muted); margin: 0 0 1rem; }

.cp-grid[b-waa0cxuadw] {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1rem;
    align-items: start;
}

.cp-wide[b-waa0cxuadw] { grid-column: 1 / -1; }

@media (max-width: 800px) {
    .cp-grid[b-waa0cxuadw] { grid-template-columns: minmax(0, 1fr); }
}

.cp-card[b-waa0cxuadw] { padding: 1rem 1.15rem; min-width: 0; }

.cp-h2[b-waa0cxuadw] { font-size: .95rem; font-weight: 700; margin: 0 0 .7rem; color: var(--ft-text); }

.cp-dl[b-waa0cxuadw] {
    display: grid;
    grid-template-columns: minmax(7rem, max-content) minmax(0, 1fr);
    gap: .45rem 1rem;
    margin: 0;
}

.cp-dl dt[b-waa0cxuadw] { font-size: .8rem; color: var(--ft-text-muted); }

.cp-dl dd[b-waa0cxuadw] { margin: 0; font-size: .88rem; color: var(--ft-text); overflow-wrap: anywhere; }

.cp-none[b-waa0cxuadw] { color: var(--ft-text-faint); font-size: .85rem; margin: 0; }

.cp-mono[b-waa0cxuadw] { font-variant-numeric: tabular-nums; letter-spacing: .02em; }

.cp-badge[b-waa0cxuadw] {
    display: inline-block; margin-left: .45rem; font-size: .68rem; font-weight: 700;
    border-radius: 999px; padding: .08rem .5rem; white-space: nowrap; border: 1px solid transparent;
    color: var(--ft-text);
}

.cp-badge-ok[b-waa0cxuadw] {
    background: color-mix(in srgb, #0f9b54 14%, var(--ft-surface));
    border-color: color-mix(in srgb, #0f9b54 35%, transparent);
}

.cp-badge-warn[b-waa0cxuadw] {
    background: color-mix(in srgb, #d97706 14%, var(--ft-surface));
    border-color: color-mix(in srgb, #d97706 35%, transparent);
}

.cp-chips[b-waa0cxuadw] { list-style: none; display: flex; flex-wrap: wrap; gap: .5rem; margin: 0; padding: 0; }

.cp-chip[b-waa0cxuadw] {
    font-size: .8rem; font-weight: 600; color: var(--ft-text);
    background: color-mix(in srgb, #d97706 10%, var(--ft-surface));
    border: 1px solid color-mix(in srgb, #d97706 30%, transparent);
    padding: .3rem .65rem; border-radius: 999px; overflow-wrap: anywhere;
}

.cp-list[b-waa0cxuadw] { margin: 0; padding-left: 1.1rem; font-size: .88rem; color: var(--ft-text); }

.cp-list li + li[b-waa0cxuadw] { margin-top: .2rem; }

.cp-overview[b-waa0cxuadw] { margin: 0; font-size: .9rem; line-height: 1.55; color: var(--ft-text); white-space: pre-line; }
/* /Components/Pages/Settings/LetterheadSettings.razor.rz.scp.css */
/* AB#2262 — the letterhead settings page. Scoped: nothing here reaches another page, and app.css is lane 0's. */

.lhs-page[b-6lau01rw1o] { max-width: 1100px; }

.lhs-muted[b-6lau01rw1o] { color: var(--ft-text-muted); }

.lhs-grid[b-6lau01rw1o] {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
    gap: 1.25rem;
    align-items: start;
}

@media (max-width: 900px) {
    .lhs-grid[b-6lau01rw1o] { grid-template-columns: minmax(0, 1fr); }
}

.lhs-editor[b-6lau01rw1o] { padding: 1.1rem 1.2rem; }

.lhs-visually-hidden[b-6lau01rw1o] {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

.lhs-toggle[b-6lau01rw1o] { display: flex; gap: .55rem; align-items: center; font-weight: 600; }

.lhs-field-label[b-6lau01rw1o] { display: block; margin-top: 1rem; }

.lhs-hint[b-6lau01rw1o] { font-size: .8rem; color: var(--ft-text-muted); margin: .3rem 0 0; line-height: 1.4; }

.lhs-logo-row[b-6lau01rw1o] { display: flex; gap: .75rem; align-items: center; flex-wrap: wrap; margin-top: .35rem; }

.lhs-logo-thumb[b-6lau01rw1o] {
    max-width: 170pt; max-height: 34pt; width: auto; height: auto; object-fit: contain;
    background: #fff; border: 1px solid var(--ft-border); border-radius: 6px; padding: 4px;
}

.lhs-upload[b-6lau01rw1o] { position: relative; overflow: hidden; cursor: pointer; }
.lhs-upload[b-6lau01rw1o]  .lhs-file { position: absolute; inset: 0; opacity: 0; cursor: pointer; }
.lhs-disabled[b-6lau01rw1o] { opacity: .55; pointer-events: none; }

.lhs-lines[b-6lau01rw1o] { width: 100%; font-family: inherit; resize: vertical; margin-top: .3rem; }
.lhs-select[b-6lau01rw1o] { max-width: 14rem; margin-top: .3rem; }

.lhs-errors[b-6lau01rw1o] {
    padding: .7rem .9rem .7rem 1.6rem;
    border-left: 3px solid var(--ft-red-text);
    background: var(--ft-surface);
    color: var(--ft-red-text);
    font-size: .86rem;
    margin: .75rem 0 0;
}
div.lhs-errors[b-6lau01rw1o] { padding-left: .9rem; }

.lhs-warn[b-6lau01rw1o] {
    padding: .6rem .8rem;
    border-radius: 8px;
    background: var(--ft-amber-bg);
    color: var(--ft-amber-text);
    font-size: .84rem;
    margin-top: .6rem;
}

.lhs-actions[b-6lau01rw1o] { display: flex; gap: .75rem; align-items: center; margin-top: 1.1rem; }
.lhs-saved[b-6lau01rw1o] { color: var(--ft-green-text); font-size: .88rem; }

.lhs-preview-title[b-6lau01rw1o] { font-size: 1rem; margin: 0; }

/* The paper: white and black whatever the app theme, because a document is. A4's proportions, so line lengths and
   the logo box read as they will on a page. */
.lhs-paper[b-6lau01rw1o] {
    margin-top: .6rem;
    background: #fff;
    color: #1a1f2b;
    aspect-ratio: 210 / 297;
    width: 100%;
    padding: 7% 8%;
    border: 1px solid var(--ft-border);
    border-radius: 4px;
    box-shadow: var(--ft-shadow-sm);
    display: flex;
    flex-direction: column;
    gap: 14pt;
    overflow: hidden;
}

.lhs-paper .lhs-hint[b-6lau01rw1o] { color: #5b6472; }

.lhs-body[b-6lau01rw1o] { flex: 1; display: flex; flex-direction: column; gap: 6pt; color: #8a919c; font-size: 9pt; }
.lhs-body p[b-6lau01rw1o] { margin: 0 0 4pt; font-style: italic; }
.lhs-bar[b-6lau01rw1o] { display: block; height: 6pt; border-radius: 3pt; background: #eceef1; }
.lhs-bar-short[b-6lau01rw1o] { width: 60%; }
/* /Components/Pages/Settings/PipelineFollowUpSettings.razor.rz.scp.css */
/* AB#2119 — the org's follow-up numbers. Scoped: nothing here reaches another page, and app.css is lane 0's. */

.fu-card[b-d3vu1uh9b8] {
    padding: .9rem 1rem;
    margin-top: 1.5rem;
}

.fu-h2[b-d3vu1uh9b8] {
    margin: 0 0 .35rem;
    font-size: 1rem;
    font-weight: 600;
}

.fu-explain[b-d3vu1uh9b8],
.fu-muted[b-d3vu1uh9b8] {
    color: var(--ft-text-muted);
    font-size: .88rem;
    margin: 0 0 .75rem;
}

.fu-fields[b-d3vu1uh9b8] {
    display: flex;
    flex-wrap: wrap;
    gap: .75rem 1.25rem;
}

.fu-field[b-d3vu1uh9b8] {
    display: flex;
    flex-direction: column;
    gap: .3rem;
    font-size: .88rem;
}

.fu-field input[b-d3vu1uh9b8] {
    width: 7rem;
}

.fu-note[b-d3vu1uh9b8],
.fu-errors[b-d3vu1uh9b8],
.fu-saved[b-d3vu1uh9b8] {
    padding: .6rem .85rem;
    border-radius: 8px;
    font-size: .88rem;
    margin-top: .75rem;
}

.fu-note[b-d3vu1uh9b8] {
    background: var(--ft-surface-2);
    color: var(--ft-text-muted);
    margin: 0 0 .75rem;
}

.fu-errors[b-d3vu1uh9b8] {
    background: var(--ft-amber-bg);
    color: var(--ft-amber-text);
}

.fu-saved[b-d3vu1uh9b8] {
    background: var(--ft-surface-2);
    color: var(--ft-text);
}

.fu-actions[b-d3vu1uh9b8] {
    margin-top: 1rem;
}
/* /Components/Pages/Settings/PipelineSettings.razor.rz.scp.css */
/* AB#1630 — the org's pipeline vocabulary editor. Scoped: nothing here reaches another page, and app.css is lane 0's. */

.ps-page[b-9m749mz0mk] {
    max-width: 760px;
}

.ps-crumb[b-9m749mz0mk] {
    display: inline-block;
    font-size: .85rem;
    margin-bottom: .5rem;
}

.ps-card[b-9m749mz0mk] {
    padding: .9rem 1rem;
    margin-top: 1rem;
}

.ps-h2[b-9m749mz0mk] {
    margin: 0 0 .6rem;
    font-size: 1rem;
    font-weight: 600;
}

.ps-head[b-9m749mz0mk],
.ps-row[b-9m749mz0mk] {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(9rem, 13rem) auto;
    gap: .5rem;
    align-items: center;
}

.ps-row-option[b-9m749mz0mk] {
    grid-template-columns: minmax(0, 1fr) auto;
}

.ps-head[b-9m749mz0mk] {
    font-size: .8rem;
    color: var(--ft-text-muted);
    margin-bottom: .3rem;
}

.ps-row[b-9m749mz0mk] {
    margin-bottom: .45rem;
}

.ps-tools[b-9m749mz0mk] {
    display: inline-flex;
    gap: .3rem;
}

.ps-add[b-9m749mz0mk] {
    margin-top: .35rem;
}

.ps-muted[b-9m749mz0mk] {
    color: var(--ft-text-muted);
}

.ps-note[b-9m749mz0mk],
.ps-inuse[b-9m749mz0mk],
.ps-errors[b-9m749mz0mk],
.ps-saved[b-9m749mz0mk] {
    padding: .6rem .85rem;
    border-radius: 8px;
    font-size: .88rem;
}

.ps-note[b-9m749mz0mk] {
    background: var(--ft-surface-2);
    color: var(--ft-text-muted);
    margin-top: .75rem;
}

.ps-inuse[b-9m749mz0mk],
.ps-errors[b-9m749mz0mk] {
    background: var(--ft-amber-bg);
    color: var(--ft-amber-text);
    margin: .25rem 0 .5rem;
}

.ps-errors[b-9m749mz0mk] {
    margin-top: 1rem;
}

.ps-saved[b-9m749mz0mk] {
    background: var(--ft-surface-2);
    color: var(--ft-text);
    margin-top: 1rem;
}

.ps-actions[b-9m749mz0mk] {
    margin-top: 1rem;
}

@media (max-width: 640px) {
    .ps-head[b-9m749mz0mk] {
        display: none;
    }

    .ps-row[b-9m749mz0mk] {
        grid-template-columns: minmax(0, 1fr);
    }
}
/* /Components/Pages/Settings/ProposalTemplatePanel.razor.rz.scp.css */
/* AB#1660 — the proposal template panel on the letterhead page. Scoped: nothing here reaches another page, and app.css
   is lane 0's. The colours are the letterhead page's own tokens, so the two cards read as one page. */

.ptp[b-pq34f2tce0] { margin-top: 1.25rem; padding: 1.1rem 1.2rem; max-width: 1100px; }

.ptp-title[b-pq34f2tce0] { font-size: 1rem; margin: 0; }
.ptp-subtitle[b-pq34f2tce0] { font-size: .9rem; margin: 1.2rem 0 0; }

.ptp-hint[b-pq34f2tce0] { font-size: .8rem; color: var(--ft-text-muted); margin: .3rem 0 0; line-height: 1.4; }
.ptp-current[b-pq34f2tce0] { margin: .75rem 0 0; font-size: .92rem; font-weight: 600; overflow-wrap: anywhere; }

.ptp-warn[b-pq34f2tce0] {
    padding: .6rem .8rem;
    border-radius: 8px;
    background: var(--ft-amber-bg);
    color: var(--ft-amber-text);
    font-size: .84rem;
    margin: .6rem 0 0;
    overflow-wrap: anywhere;
}

.ptp-actions[b-pq34f2tce0] { display: flex; gap: .75rem; align-items: center; flex-wrap: wrap; margin-top: 1rem; }

/* The file input covers its label, invisible, so the whole button is the picker (the letterhead page's logo pattern). */
.ptp-upload[b-pq34f2tce0] { position: relative; overflow: hidden; cursor: pointer; }
.ptp-upload[b-pq34f2tce0]  input[type=file] { position: absolute; inset: 0; opacity: 0; cursor: pointer; }
.ptp-upload.is-busy[b-pq34f2tce0] { opacity: .55; pointer-events: none; }

.ptp-saved[b-pq34f2tce0] { color: var(--ft-green-text); font-size: .88rem; margin: .6rem 0 0; }

.ptp-errors[b-pq34f2tce0] {
    padding: .7rem .9rem;
    border-left: 3px solid var(--ft-red-text);
    background: var(--ft-surface);
    color: var(--ft-red-text);
    font-size: .86rem;
    margin: .75rem 0 0;
}

.ptp-fields[b-pq34f2tce0] {
    display: grid;
    grid-template-columns: max-content minmax(0, 1fr);
    gap: .35rem 1rem;
    margin: .6rem 0 0;
    font-size: .84rem;
}
.ptp-fields dt[b-pq34f2tce0] { margin: 0; }
.ptp-fields dd[b-pq34f2tce0] { margin: 0; color: var(--ft-text-muted); }
.ptp-fields code[b-pq34f2tce0] { font-size: .8rem; }

@media (max-width: 600px) {
    .ptp-fields[b-pq34f2tce0] { grid-template-columns: minmax(0, 1fr); }
    .ptp-fields dd[b-pq34f2tce0] { margin-bottom: .4rem; }
}
/* /Components/Pages/Settings/RememberedLayouts.razor.rz.scp.css */
/* ═══════════════════════════════════════════════════════════════════════════════════════════════
   Remembered bid-form layouts (AB#1741).

   Its own file, like every estimating surface since AB#1732 — app.css is the one file three lanes would
   all have to edit to do UI at once. Tokens, never literal colours: a hex looks right in the screenshot
   and wrong at night.
   ═══════════════════════════════════════════════════════════════════════════════════════════════ */

.wrap[b-cyaugo5dja] {
    max-width: 900px;
}

.crumb[b-cyaugo5dja] {
    font-size: .85rem;
    color: var(--ft-text-muted);
    text-decoration: none;
}

.crumb:hover[b-cyaugo5dja] { color: var(--ft-text); }

.muted[b-cyaugo5dja] { color: var(--ft-text-muted); }

/* A confirmed layout can carry six roles, so this row is wider than a phone. It scrolls inside its own
   box; the page body never scrolls sideways. */
.table-wrap[b-cyaugo5dja] { overflow-x: auto; }

.layouts[b-cyaugo5dja] { width: 100%; }

.layouts th[b-cyaugo5dja] {
    text-align: left;
    font-size: .8rem;
    font-weight: 650;
    color: var(--ft-text-muted);
    white-space: nowrap;
}

.layouts td[b-cyaugo5dja] { vertical-align: top; }

.label[b-cyaugo5dja] {
    font-weight: 600;
    color: var(--ft-navy);
}

/* The only thing that tells two unnamed confirmations apart, and what a support conversation quotes.
   Monospaced so a hash can be compared character by character rather than read. */
.fingerprint[b-cyaugo5dja] {
    font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
    font-size: .72rem;
    color: var(--ft-text-faint);
    letter-spacing: .02em;
}

.cols[b-cyaugo5dja] {
    display: flex;
    flex-wrap: wrap;
    gap: .3rem;
}

/* Role and column together in one chip. Split across two columns of the table they would have to be
   read as parallel lists, which is the shape that lets a reader pair the wrong two. */
.col-chip[b-cyaugo5dja] {
    display: inline-flex;
    align-items: baseline;
    gap: .3rem;
    padding: .12rem .45rem;
    border: 1px solid var(--ft-border);
    border-radius: 999px;
    background: var(--ft-surface-2);
    font-size: .76rem;
    font-variant-numeric: tabular-nums;
    color: var(--ft-navy);
    white-space: nowrap;
}

.col-role[b-cyaugo5dja] {
    color: var(--ft-text-muted);
    font-size: .72rem;
}

.when[b-cyaugo5dja] {
    color: var(--ft-text-muted);
    font-size: .82rem;
    white-space: nowrap;
}

.right[b-cyaugo5dja] { text-align: right; }

.alert[b-cyaugo5dja] {
    padding: .85rem 1rem;
    margin-bottom: 1rem;
    border-left: 3px solid var(--ft-red, #b91c1c);
    border-radius: 6px;
    background: var(--ft-surface-2);
    color: var(--ft-navy);
    font-size: .88rem;
}

.ok[b-cyaugo5dja] {
    margin-bottom: 1rem;
    font-size: .88rem;
    color: var(--ft-green-text, #166534);
}
/* /Components/Pages/Settings/TradePartnersSettings.razor.rz.scp.css */
/* AB#1896 — the trade-partner register. Scoped: nothing here reaches another page, and app.css is lane 0's. */

.tp-page[b-84dukoyr7k] {
    max-width: 1080px;
}

.tp-crumb[b-84dukoyr7k] {
    display: inline-block;
    font-size: .85rem;
    margin-bottom: .5rem;
}

.tp-card[b-84dukoyr7k] {
    padding: .9rem 1rem;
    margin-top: 1rem;
}

.tp-h2[b-84dukoyr7k] {
    margin: 0 0 .6rem;
    font-size: 1rem;
    font-weight: 600;
}

.tp-h3[b-84dukoyr7k] {
    margin: .9rem 0 .45rem;
    font-size: .9rem;
    font-weight: 600;
}

.tp-muted[b-84dukoyr7k] {
    color: var(--ft-text-muted);
}

.tp-explain[b-84dukoyr7k] {
    font-size: .88rem;
    margin: 0 0 .75rem;
}

.tp-toolbar[b-84dukoyr7k] {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: center;
    gap: .5rem;
    margin-bottom: .75rem;
}

.tp-filters[b-84dukoyr7k] {
    display: inline-flex;
    flex-wrap: wrap;
    gap: .3rem;
}

.tp-table-wrap[b-84dukoyr7k] {
    overflow-x: auto;
}

.tp-table td[b-84dukoyr7k] {
    vertical-align: top;
}

/* Razor trims the space a literal would carry before "+1 more"; measured in a browser as "Ana Duarte+1 more". */
.tp-more[b-84dukoyr7k] {
    margin-left: .3rem;
}

.tp-badge[b-84dukoyr7k] {
    margin-left: .35rem;
}

.tp-row-off td[b-84dukoyr7k] {
    color: var(--ft-text-muted);
}

.tp-badge-off[b-84dukoyr7k] {
    opacity: .7;
}

.tp-editor[b-84dukoyr7k] {
    border: 1px solid var(--ft-border-strong);
    border-radius: 8px;
    padding: .85rem 1rem;
    margin-bottom: 1rem;
    background: var(--ft-surface-2);
}

.tp-grid[b-84dukoyr7k] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
    gap: .6rem 1rem;
}

.tp-field[b-84dukoyr7k] {
    display: flex;
    flex-direction: column;
    gap: .25rem;
    font-size: .85rem;
}

.tp-checks[b-84dukoyr7k] {
    display: flex;
    flex-wrap: wrap;
    gap: 1.25rem;
    margin-top: .6rem;
    font-size: .88rem;
}

.tp-contact[b-84dukoyr7k] {
    display: grid;
    grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr) minmax(0, 1.4fr) minmax(0, 1fr) minmax(0, 1fr) auto;
    gap: .4rem;
    margin-bottom: .4rem;
}

.tp-sys-head[b-84dukoyr7k],
.tp-sys-row[b-84dukoyr7k] {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(10rem, 14rem) minmax(10rem, 16rem) auto;
    gap: .5rem;
    align-items: center;
}

.tp-sys-head[b-84dukoyr7k] {
    font-size: .8rem;
    color: var(--ft-text-muted);
    margin-bottom: .3rem;
}

.tp-sys-row[b-84dukoyr7k] {
    margin-bottom: .45rem;
}

.tp-actions[b-84dukoyr7k] {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    margin-top: .85rem;
}

.tp-delete[b-84dukoyr7k] {
    margin-left: auto;
}

.tp-confirm[b-84dukoyr7k] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .5rem;
    margin-top: .6rem;
    padding: .6rem .85rem;
    border-radius: 8px;
    background: var(--ft-amber-bg);
    color: var(--ft-amber-text);
    font-size: .88rem;
}

.tp-errors[b-84dukoyr7k],
.tp-saved[b-84dukoyr7k] {
    padding: .6rem .85rem;
    border-radius: 8px;
    font-size: .88rem;
    margin-top: .75rem;
}

.tp-errors[b-84dukoyr7k] {
    background: var(--ft-amber-bg);
    color: var(--ft-amber-text);
}

.tp-saved[b-84dukoyr7k] {
    background: var(--ft-surface-2);
    color: var(--ft-text);
}

.tp-preview[b-84dukoyr7k] {
    margin-top: .85rem;
}

.tp-skips[b-84dukoyr7k] {
    margin: 0;
    padding-left: 1.2rem;
    font-size: .88rem;
}

@media (max-width: 760px) {
    .tp-contact[b-84dukoyr7k],
    .tp-sys-row[b-84dukoyr7k] {
        grid-template-columns: minmax(0, 1fr);
    }

    .tp-sys-head[b-84dukoyr7k] {
        display: none;
    }

    .tp-contact > button[b-84dukoyr7k],
    .tp-sys-row > button[b-84dukoyr7k] {
        justify-self: start;
    }
}
/* /Components/Shared/JobPartiesPanel.razor.rz.scp.css */
/* AB#1975 — the job's parties on the identity header. Declared theme tokens only (app.css :root and its dark
   twin), with no hex fallbacks: a var(--ft-x, #hex) whose token is declared in neither theme paints the light
   colour on a dark card, which is how --ft-success and --ft-danger went unnoticed. */

.jp[b-1q5933cope] {
    margin-top: .4rem;
    font-size: .8rem;
}

.jp-strip[b-1q5933cope] {
    display: flex;
    flex-wrap: wrap;
    gap: .35rem .9rem;
    margin: 0 0 .25rem;
    padding: 0;
    list-style: none;
}

.jp-item[b-1q5933cope] {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: .35rem;
    min-width: 0;
}

.jp-role[b-1q5933cope] {
    font-size: .68rem;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--ft-text-faint);
}

.jp-name[b-1q5933cope] {
    font-weight: 600;
    color: var(--ft-text);
    overflow-wrap: anywhere;
}

.jp-contact[b-1q5933cope] {
    color: var(--ft-accent);
    text-decoration: none;
    overflow-wrap: anywhere;
}

.jp-link[b-1q5933cope] {
    padding: 0;
    border: none;
    background: transparent;
    font-size: .78rem;
    font-weight: 600;
    color: var(--ft-accent);
    cursor: pointer;
}

.jp-editor[b-1q5933cope] {
    margin-top: .5rem;
    padding: .75rem 1rem;
    border: 1px solid var(--ft-border);
    border-radius: var(--ft-radius);
    background: var(--ft-surface-2);
}

.jp-editor-title[b-1q5933cope] {
    font-size: .85rem;
    font-weight: 700;
    color: var(--ft-text);
}

.jp-intro[b-1q5933cope] {
    margin: .15rem 0 .6rem;
    color: var(--ft-text-muted);
}

.jp-row[b-1q5933cope] {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: .5rem;
    padding: .5rem 0;
    border-top: 1px solid var(--ft-border-soft);
}

.jp-field[b-1q5933cope] {
    display: flex;
    flex-direction: column;
    gap: .15rem;
    min-width: 9rem;
}

.jp-field > span[b-1q5933cope] {
    font-size: .7rem;
    font-weight: 600;
    color: var(--ft-text-muted);
}

.jp-grow[b-1q5933cope] {
    flex: 1 1 12rem;
}

.jp-permit[b-1q5933cope] {
    max-width: 18rem;
    margin-bottom: .4rem;
}

.jp-error[b-1q5933cope] {
    margin-top: .5rem;
    font-weight: 600;
    color: var(--ft-red-text);
}

.jp-actions[b-1q5933cope] {
    display: flex;
    gap: .5rem;
    margin-top: .6rem;
}
/* /Components/Shared/LetterheadFoot.razor.rz.scp.css */
/* AB#2262 — the letterhead foot, scoped. Sizes come inline from LetterheadLayout; ink inherited, a step lighter. */
.lh-foot[b-ykux8zr0ch] { display: flex; flex-direction: column; gap: 1pt; padding-top: 4pt; color: inherit; opacity: .78;
    border-top: .5pt solid color-mix(in srgb, currentColor 30%, transparent); }
.lh-line[b-ykux8zr0ch] { line-height: 1.3; overflow-wrap: anywhere; }
.lh-align-left[b-ykux8zr0ch] { align-items: flex-start; text-align: left; }
.lh-align-centre[b-ykux8zr0ch] { align-items: center; text-align: center; }
.lh-align-right[b-ykux8zr0ch] { align-items: flex-end; text-align: right; }
/* /Components/Shared/LetterheadHead.razor.rz.scp.css */
/* AB#2262 — the letterhead head, scoped. Sizes come inline from LetterheadLayout (points, shared with the PDF
   renderer); only layout lives here. Ink is INHERITED: the surface it sits on (the preview's paper, a printed sheet)
   decides the colour, so it is black on paper whatever the app's theme. */
.lh-head[b-vhxhb1kr36] { display: flex; flex-direction: column; gap: 1.5pt; padding-bottom: 6pt; color: inherit;
    border-bottom: 1.5pt solid color-mix(in srgb, currentColor 22%, transparent); }
.lh-logo[b-vhxhb1kr36] { display: block; width: auto; height: auto; object-fit: contain; margin-bottom: 3pt; }
.lh-line[b-vhxhb1kr36] { line-height: 1.3; overflow-wrap: anywhere; }
.lh-align-left[b-vhxhb1kr36] { align-items: flex-start; text-align: left; }
.lh-align-centre[b-vhxhb1kr36] { align-items: center; text-align: center; }
.lh-align-right[b-vhxhb1kr36] { align-items: flex-end; text-align: right; }
/* /Components/Shared/SiteView3D.razor.rz.scp.css */
/* AB#2231 — SiteView3D. Declared theme tokens only (app.css :root and its light twin), with no hex fallbacks: a
   var(--ft-x, #hex) whose token is declared in neither theme paints the light colour on a dark card, which is how
   --ft-success and --ft-danger went unnoticed. The canvas, its labels and its tooltip are drawn by site-view-3d.js
   inside .sv3d-stage and style themselves from the same tokens; nothing here reaches into them. */

.sv3d[b-0mfb6k52w2] {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 17.5rem;
    gap: .75rem;
    align-items: start;
}

.sv3d-main[b-0mfb6k52w2] {
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: .5rem;
}

.sv3d-toolbar[b-0mfb6k52w2] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: .5rem;
}

.sv3d-scale[b-0mfb6k52w2] {
    display: inline-flex;
    align-items: center;
    padding: .2rem .6rem;
    border-radius: 999px;
    border: 1px solid var(--ft-border);
    background: var(--ft-surface-2);
    color: var(--ft-text-muted);
    font-size: .75rem;
    font-weight: 600;
}

.sv3d-tools[b-0mfb6k52w2] {
    display: flex;
    align-items: center;
    gap: .5rem;
    margin-left: auto;
}

.sv3d-seg[b-0mfb6k52w2],
.sv3d-zoom[b-0mfb6k52w2] {
    display: inline-flex;
    padding: 3px;
    gap: 2px;
    border: 1px solid var(--ft-border);
    border-radius: var(--ft-radius);
    background: var(--ft-surface-2);
}

.sv3d-seg-btn[b-0mfb6k52w2],
.sv3d-icon[b-0mfb6k52w2] {
    border: 0;
    background: none;
    color: var(--ft-text-muted);
    font: inherit;
    font-size: .8rem;
    font-weight: 600;
    min-width: 2.25rem;
    height: 1.9rem;
    padding: 0 .6rem;
    border-radius: var(--ft-radius-sm);
    cursor: pointer;
    display: inline-grid;
    place-items: center;
}

.sv3d-icon[b-0mfb6k52w2] {
    padding: 0;
    width: 2rem;
    min-width: 2rem;
}

.sv3d-icon svg[b-0mfb6k52w2] {
    width: 1rem;
    height: 1rem;
    fill: none;
    stroke: currentColor;
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.sv3d-seg-btn.on[b-0mfb6k52w2] {
    background: var(--ft-surface);
    color: var(--ft-text);
    box-shadow: var(--ft-shadow-xs);
}

.sv3d-seg-btn:hover:not(:disabled)[b-0mfb6k52w2],
.sv3d-icon:hover:not(:disabled)[b-0mfb6k52w2] {
    color: var(--ft-text);
}

.sv3d-seg-btn:disabled[b-0mfb6k52w2],
.sv3d-icon:disabled[b-0mfb6k52w2] {
    opacity: .45;
    cursor: not-allowed;
}

.sv3d-seg-btn:focus-visible[b-0mfb6k52w2],
.sv3d-icon:focus-visible[b-0mfb6k52w2],
.sv3d-item:focus-visible[b-0mfb6k52w2] {
    outline: 2px solid var(--ft-accent);
    outline-offset: 2px;
}

.sv3d-stage[b-0mfb6k52w2],
.sv3d-unavailable[b-0mfb6k52w2] {
    position: relative;
    width: 100%;
    min-height: 16rem;
    border: 1px solid var(--ft-border);
    border-radius: var(--ft-radius-lg);
    background: var(--ft-surface-2);
    overflow: hidden;
}

.sv3d-unavailable[b-0mfb6k52w2] {
    display: grid;
    place-items: center;
    padding: 1.5rem;
    text-align: center;
    color: var(--ft-text-muted);
    font-size: .9rem;
}

.sv3d-fallback[b-0mfb6k52w2] {
    margin: 0;
    padding: .45rem .7rem;
    border-radius: var(--ft-radius-sm);
    background: var(--ft-amber-bg);
    color: var(--ft-amber-text);
    font-size: .8rem;
}

/* ── the list: the keyboard-reachable mirror of the canvas ───────────────────────────────────────────────────────── */

.sv3d-list[b-0mfb6k52w2] {
    min-width: 0;
    max-height: 640px;
    overflow: auto;
    padding: .75rem;
    border: 1px solid var(--ft-border);
    border-radius: var(--ft-radius-lg);
    background: var(--ft-surface);
}

.sv3d-list-h[b-0mfb6k52w2] {
    margin: 0 0 .5rem;
    font-size: .8rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--ft-text-muted);
}

.sv3d-sub[b-0mfb6k52w2] {
    margin: .75rem 0 .3rem;
    font-size: .72rem;
    font-weight: 700;
    color: var(--ft-text-faint);
    text-transform: uppercase;
    letter-spacing: .04em;
}

.sv3d-empty[b-0mfb6k52w2] {
    margin: 0;
    padding: .6rem .7rem;
    border: 1px dashed var(--ft-border);
    border-radius: var(--ft-radius-sm);
    color: var(--ft-text-muted);
    font-size: .8rem;
}

.sv3d-items[b-0mfb6k52w2],
.sv3d-legend[b-0mfb6k52w2] {
    list-style: none;
    margin: 0;
    padding: 0;
}

.sv3d-legend[b-0mfb6k52w2] {
    display: grid;
    gap: .3rem;
    padding: .5rem .6rem;
    border-radius: var(--ft-radius-sm);
    background: var(--ft-surface-2);
}

.sv3d-legend li[b-0mfb6k52w2] {
    display: flex;
    align-items: center;
    gap: .45rem;
    font-size: .78rem;
    color: var(--ft-text-muted);
}

.sv3d-legend b[b-0mfb6k52w2] {
    margin-left: auto;
    color: var(--ft-text);
}

.sv3d-item[b-0mfb6k52w2] {
    width: 100%;
    display: flex;
    align-items: flex-start;
    gap: .55rem;
    padding: .4rem .5rem;
    border: 1px solid transparent;
    border-radius: var(--ft-radius-sm);
    background: none;
    color: var(--ft-text);
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.sv3d-item:hover[b-0mfb6k52w2] {
    background: var(--ft-surface-2);
}

.sv3d-item.on[b-0mfb6k52w2] {
    background: var(--ft-orange-100);
    border-color: var(--ft-orange-200);
}

.sv3d-item-text[b-0mfb6k52w2] {
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.sv3d-item-text b[b-0mfb6k52w2] {
    font-size: .82rem;
    font-weight: 600;
    overflow-wrap: anywhere;
}

.sv3d-item-text small[b-0mfb6k52w2] {
    font-size: .74rem;
    color: var(--ft-text-muted);
}

.sv3d-item-text .sv3d-trip[b-0mfb6k52w2] {
    color: var(--ft-accent);
    font-weight: 600;
}

/* Pin glyphs: the SAME shape the canvas draws, so the list and the legend teach the canvas. */
.sv3d-glyph[b-0mfb6k52w2] {
    width: 1rem;
    height: 1rem;
    flex: none;
    margin-top: .1rem;
    fill: currentColor;
    stroke: currentColor;
}

.sv3d-glyph-photo[b-0mfb6k52w2] { color: var(--ft-green); }
.sv3d-glyph-empty[b-0mfb6k52w2] { color: var(--ft-text-faint); }
.sv3d-glyph-defect[b-0mfb6k52w2] { color: var(--ft-red); }
.sv3d-glyph-crew[b-0mfb6k52w2] { color: var(--ft-blue); }
.sv3d-glyph-asset[b-0mfb6k52w2] { color: var(--ft-purple); }

.sv3d-zone-swatch[b-0mfb6k52w2] {
    width: .7rem;
    height: .7rem;
    flex: none;
    margin-top: .25rem;
    border-radius: 2px;
    background: var(--ft-blue-bg);
    border: 1.5px solid var(--ft-blue);
}

/* Site status: told apart by shape as well as colour — a ring for failed, a triangle for attention, a dot otherwise. */
.sv3d-status[b-0mfb6k52w2] {
    width: .7rem;
    height: .7rem;
    flex: none;
    margin-top: .3rem;
    border-radius: 50%;
}

.sv3d-status-ok[b-0mfb6k52w2] { background: var(--ft-green); }

.sv3d-status-amber[b-0mfb6k52w2] {
    border-radius: 0;
    background: var(--ft-amber);
    clip-path: polygon(50% 0, 100% 100%, 0 100%);
}

.sv3d-status-failed[b-0mfb6k52w2] {
    background: var(--ft-red);
    box-shadow: 0 0 0 2px var(--ft-surface), 0 0 0 3.5px var(--ft-red);
}

@media (max-width: 960px) {
    .sv3d[b-0mfb6k52w2] {
        grid-template-columns: minmax(0, 1fr);
    }

    .sv3d-list[b-0mfb6k52w2] {
        max-height: none;
    }
}

/* ── AB#2287: floating (the Overview's board) ─────────────────────────────────────────────────────────────────────────
   The section and its main column step out of the box tree (display: contents), so the stage, the toolbar and the
   fallback sentence become items of the PAGE's grid, which places them (SitesOverview.razor.css): the scene in its own
   area with the cards around it, the tools in their own row above it. A floating board draws no list of its own; the
   page's Sites card is the list. The job's site view does not set Floating and is untouched by every rule below. */

.sv3d.sv3d-floating[b-0mfb6k52w2],
.sv3d-floating .sv3d-main[b-0mfb6k52w2] {
    display: contents;
}

/* The toolbar is not a card: its pills (the honesty line, the 3D | 2D and zoom groups) sit in their own row and wrap
   into two short rows when the middle of the page is narrow. */
.sv3d-floating .sv3d-toolbar[b-0mfb6k52w2] {
    max-width: 100%;
    justify-content: center;
}

.sv3d-floating .sv3d-scale[b-0mfb6k52w2],
.sv3d-floating .sv3d-seg[b-0mfb6k52w2],
.sv3d-floating .sv3d-zoom[b-0mfb6k52w2] {
    background: var(--ft-surface);
    box-shadow: var(--ft-shadow-xs);
}

.sv3d-floating .sv3d-tools[b-0mfb6k52w2] {
    margin-left: 0;
}

.sv3d-floating .sv3d-fallback[b-0mfb6k52w2] {
    box-shadow: var(--ft-shadow-sm);
}
/* /Components/Shared/SiteViewHelpLink.razor.rz.scp.css */
/* AB#2241 — a quiet text link in a page header; the page places it (JobSiteView pushes it to the row's end). */
.svh-link[b-a2ffwi46m1] { color: var(--ft-accent); font-weight: 600; font-size: .82rem; white-space: nowrap; text-decoration: none; }
.svh-link:hover[b-a2ffwi46m1], .svh-link:focus-visible[b-a2ffwi46m1] { text-decoration: underline; }
/* /Components/Shared/StartPageChooser.razor.rz.scp.css */
/* AB#2235: the account menu's Start page block. It is the same shape as the menu's Theme and Language blocks
   (MainLayout's inline styles), from tokens declared in both themes. A select, not a pill row: three or four
   choices in German do not fit a 268px menu as buttons. */
.sp-block[b-wp98b20w37] {
    padding: .75rem 1rem;
    border-bottom: 1px solid var(--ft-border-soft);
}

.sp-label[b-wp98b20w37] {
    display: block;
    font-size: .7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .05em;
    color: var(--ft-text-faint);
    margin-bottom: .4rem;
}

.sp-select[b-wp98b20w37] {
    width: 100%;
    padding: .35rem .5rem;
    border-radius: 6px;
    border: 1px solid var(--ft-border);
    background: var(--ft-surface);
    color: var(--ft-text);
    font-size: .78rem;
}

.sp-select:focus-visible[b-wp98b20w37] {
    outline: 2px solid var(--ft-accent);
    outline-offset: 1px;
}

.sp-note[b-wp98b20w37] {
    margin-top: .4rem;
    font-size: .72rem;
    line-height: 1.4;
    color: var(--ft-text-faint);
}

.sp-error[b-wp98b20w37] {
    color: var(--ft-red);
}
/* /Components/Shared/WatermarkStrip.razor.rz.scp.css */
/* AB#617 watermark view-time overlay (canvas 1c). Mirrors the SkiaSharp export burn: two subtle
   bands, white text, co-brand up top. Scoped to WatermarkStrip. */

.ftwm[b-cvsbvnyni8] {
    position: absolute;
    inset: 0;
    pointer-events: none;
    z-index: 5;
    font-family: ui-sans-serif, system-ui, "Segoe UI", Roboto, sans-serif;
}

/* Faint dark gradient at each edge — never a solid bar; the fade + text shadow carry legibility. */
.ftwm-band[b-cvsbvnyni8] {
    position: absolute;
    left: 0;
    right: 0;
    display: flex;
    justify-content: space-between;
    gap: 16px;
    padding: 12px 18px;
    color: #fff;
}

.ftwm-top[b-cvsbvnyni8] {
    top: 0;
    align-items: flex-start;
    background: linear-gradient(to bottom, rgba(0, 0, 0, var(--ftwm-op, 0.28)), transparent);
}

.ftwm-bottom[b-cvsbvnyni8] {
    bottom: 0;
    align-items: flex-end;
    background: linear-gradient(to top, rgba(0, 0, 0, var(--ftwm-op, 0.28)), transparent);
}

.ftwm-primary[b-cvsbvnyni8] {
    font-weight: 500;
    font-size: 13px;
    letter-spacing: 0.01em;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
}

.ftwm-sub[b-cvsbvnyni8] {
    margin-top: 2px;
    font-size: 12px;
    color: rgba(255, 255, 255, 0.85);
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
}

.ftwm-cobrand[b-cvsbvnyni8] {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-shrink: 0;
}

.ftwm-mark[b-cvsbvnyni8] {
    height: 20px;
    width: auto;
}

.ftwm-brand[b-cvsbvnyni8] {
    font-weight: 600;
    font-size: 13px;
    letter-spacing: 0.02em;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
}

.ftwm-div[b-cvsbvnyni8] {
    width: 1px;
    height: 18px;
    background: rgba(255, 255, 255, 0.5);
}

/* Customer logo mirrors the burn's light monochrome so it reads on the dark band. */
.ftwm-custlogo[b-cvsbvnyni8] {
    height: 20px;
    width: auto;
    filter: grayscale(1) brightness(2.4) contrast(0.85);
    opacity: 0.9;
}

.ftwm-gps[b-cvsbvnyni8],
.ftwm-time[b-cvsbvnyni8] {
    font-size: 12px;
    font-variant-numeric: tabular-nums;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
}

.ftwm-time[b-cvsbvnyni8] {
    font-weight: 500;
    flex-shrink: 0;
}
