﻿html, body {
    font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}

/* Prevent FOUC during Blazor enhanced navigation layout transitions */
.app-layout {
    opacity: 1;
    transition: opacity 0.1s ease-in-out;
}

/* Smooth navbar background transitions between layouts */
.app-navbar {
    transition: background 0.2s ease-in-out, background-color 0.2s ease-in-out !important;
}

/* Smooth sidebar transitions between layouts */
.app-sidebar {
    transition: background-color 0.2s ease-in-out, border-color 0.2s ease-in-out, width 0.2s ease-in-out !important;
}

a, .btn-link {
    color: var(--color-text-link);
}

a:hover, .btn-link:hover {
    color: var(--color-text-link-hover);
}

.content {
    padding-top: 1.1rem;
}

:root {
    --app-sidebar-width: 60px;
}

h1:focus {
    outline: none;
}

.valid.modified:not([type=checkbox]) {
    outline: 1px solid var(--color-success);
}

.invalid {
    outline: 1px solid var(--color-error);
}

.validation-message {
    color: var(--color-error);
}

.blazor-error-boundary {
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
    padding: 1rem 1rem 1rem 3.7rem;
    color: white;
}

    .blazor-error-boundary::after {
        content: "An error has occurred."
    }

.darker-border-checkbox.form-check-input {
    border-color: var(--color-border);
}

.form-floating > .form-control-plaintext::placeholder, .form-floating > .form-control::placeholder {
    color: var(--color-text-muted);
    text-align: end;
}

.form-floating > .form-control-plaintext:focus::placeholder, .form-floating > .form-control:focus::placeholder {
    text-align: start;
}

.form-floating > label {
    color: var(--color-text-secondary);
}

/* DataGrid section wrapper for pages without cards */
.datagrid-section {
    margin-top: 1rem;
}

.page-header-title {
    margin-bottom: .5rem !important;
}

/* .focus-mode .page-header-title {
    visibility: hidden;
    margin: 0;
    height: 0;
} */

.page-header-description {
    color: var(--color-text-secondary) !important;
    margin-bottom: 1.5rem !important;
}

.focus-mode .page-header-description {
    visibility: hidden;
    margin: 0;
    height: 0;
}

/* Project Database grid container - constrain to viewport */
.project-grid-container {
    height: calc(100vh - 200px + var(--compact-height-bonus, 0px));
    width: 100%;
    max-width: 100%;
    overflow: hidden;
    display: flex;
    flex-direction: column;
}

.focus-mode .project-grid-container {
    height: calc(100vh - 150px + var(--compact-height-bonus, 0px));
}

.project-grid-container .rz-data-grid {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-height: 0;
    width: 100%;
    overflow: hidden;
}

.project-grid-container .rz-data-grid-container {
    flex: 1;
    overflow: auto;
    min-height: 0;
}

/* Bid Tracker grid container - constrain to viewport */
.bid-grid-container {
    height: calc(100vh - 280px + var(--compact-height-bonus, 0px));
    width: 100%;
    max-width: 100%;
    overflow: hidden;
    display: flex;
    flex-direction: column;
}

.bid-grid-container .rz-data-grid {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-height: 0;
    width: 100%;
    overflow: hidden;
}

.bid-grid-container .rz-data-grid-container {
    flex: 1;
    overflow: auto;
    min-height: 0;
}

/* =============================================================================
   Reconnection Modal - Custom bilingual reconnection UI
   ============================================================================= */

#components-reconnect-modal {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 99999;
}

#components-reconnect-modal.components-reconnect-show,
#components-reconnect-modal.components-reconnect-failed,
#components-reconnect-modal.components-reconnect-rejected {
    display: block;
}

.reconnect-backdrop {
    position: absolute;
    inset: 0;
    background-color: rgba(0, 0, 0, 0.5);
    backdrop-filter: blur(2px);
}

.reconnect-dialog {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    background-color: var(--color-card-bg, #fff);
    border-radius: 8px;
    padding: 2rem;
    min-width: 320px;
    max-width: 90vw;
    box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
    text-align: center;
}

.reconnect-content {
    display: none;
}

/* Show attempting content when reconnecting */
#components-reconnect-modal.components-reconnect-show .reconnect-attempting {
    display: block;
}

/* Show failed content when failed or rejected */
#components-reconnect-modal.components-reconnect-failed .reconnect-failed-content,
#components-reconnect-modal.components-reconnect-rejected .reconnect-failed-content {
    display: block;
}

.reconnect-spinner {
    width: 48px;
    height: 48px;
    border: 4px solid var(--color-border, #e9ecef);
    border-top-color: var(--color-accent, #0d6efd);
    border-radius: 50%;
    margin: 0 auto 1rem;
    animation: reconnect-spin 1s linear infinite;
}

@keyframes reconnect-spin {
    to { transform: rotate(360deg); }
}

.reconnect-icon {
    width: 48px;
    height: 48px;
    margin: 0 auto 1rem;
    color: var(--color-warning, #ffc107);
}

.reconnect-message {
    font-size: 1rem;
    color: var(--color-text, #212529);
    margin: 0 0 1.5rem;
    line-height: 1.5;
}

.reconnect-reload-btn {
    display: inline-block;
    padding: 0.625rem 1.5rem;
    font-size: 1rem;
    font-weight: 500;
    color: #fff;
    background-color: var(--color-accent, #0d6efd);
    border: none;
    border-radius: 6px;
    cursor: pointer;
    transition: background-color 0.15s ease-in-out;
}

.reconnect-reload-btn:hover {
    background-color: var(--color-accent-hover, #0b5ed7);
}

/* Language visibility - hide non-matching language */
#components-reconnect-modal[data-lang="en"] .lang-es,
#components-reconnect-modal[data-lang="es"] .lang-en {
    display: none;
}

/* Bulk assignment dialog - between modal-lg (800px) and modal-xl (1140px) */
.modal-dialog.bulk-assign-modal {
    max-width: 950px;
}

/* ============================================================
   Compact viewport — applied via JS class on <html> when
   window.innerWidth < 1200 (zoom or small screen).
   ============================================================ */

:root {
    --compact-height-bonus: 0px;
}

.viewport-compact {
    --compact-height-bonus: 60px;
}

.viewport-compact .page-header-description {
    display: none;
}

.viewport-compact .page-header-title {
    font-size: 1.1rem;
    margin-bottom: 0.25rem !important;
}

.viewport-compact .container-fluid.py-3 {
    padding-top: 0.25rem !important;
    padding-bottom: 0.25rem !important;
}

.viewport-compact .container-fluid.py-4 {
    padding-top: 0.5rem !important;
    padding-bottom: 0.5rem !important;
}

.viewport-compact .container-fluid.mt-4 {
    margin-top: 0.5rem !important;
}

.viewport-compact .datagrid-section {
    margin-top: 0.25rem;
}

.viewport-compact .app-navbar .navbar-brand img {
    height: 24px;
}

.viewport-compact .app-navbar .bi {
    font-size: 1rem;
}

.viewport-compact .app-navbar .breadcrumb {
    font-size: 0.8rem;
}

/* Override Bootstrap col-lg-4 so 3-column cards go to 2-column earlier */
.viewport-compact .row > .col-lg-4 {
    flex: 0 0 50%;
    max-width: 50%;
}

/* ============================================================
   Narrow viewport — applied via JS class on <html> when
   window.innerWidth < 800 (high zoom or very small screen).
   ============================================================ */

.viewport-narrow {
    --compact-height-bonus: 80px;
}

.viewport-narrow .page-header-title {
    font-size: 1rem;
}

.viewport-narrow .row > .col-lg-4 {
    flex: 0 0 100%;
    max-width: 100%;
}

.text-purple {
    color: #6f42c1;
}

.text-orange {
    color: #fd7e14;
}

/* Lighter grouping cards for the Job Notes tabs — slate header with a small uppercase caption. */
.jobnotes-group {
    border: 1px solid #e3e6ea;
    border-radius: 0.375rem;
}

.jobnotes-group .card-header {
    background: #2c3e50;
    border-bottom: 1px solid #2c3e50;
    padding: 0.4rem 0.75rem;
}

.jobnotes-group .card-header h6 {
    font-size: 0.72rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: #ffffff;
}

/* Keep the Add button readable on the dark header. */
.jobnotes-group .card-header .btn-outline-primary {
    color: #ffffff;
    border-color: rgba(255, 255, 255, 0.6);
}

.jobnotes-group .card-header .btn-outline-primary:hover {
    background-color: #ffffff;
    color: #2c3e50;
    border-color: #ffffff;
}

.jobnotes-group .card-body {
    padding: 0.75rem;
}

.jobnotes-group .form-label {
    font-size: 0.75rem;
    margin-bottom: 0.15rem;
    color: #6c757d;
}

/* ---------------------------------------------------------------------------
   Per-tab Job Notes header colors. The hues come from the source
   "2026 JOB NOTES.xlsx" section-header fills, softened (hue-preserved) for a
   cleaner on-screen look.
   --------------------------------------------------------------------------- */
.jobnotes-palette .jobnotes-group--project .card-header { background: #77226E; border-bottom-color: #77226E; }
.jobnotes-palette .jobnotes-group--labor .card-header { background: #1A5B24; border-bottom-color: #1A5B24; }
.jobnotes-palette .jobnotes-group--material .card-header { background: #864827; border-bottom-color: #864827; }
.jobnotes-palette .jobnotes-group--insurance .card-header { background: #545454; border-bottom-color: #545454; }
.jobnotes-palette .jobnotes-group--ar .card-header { background: #365877; border-bottom-color: #365877; }

/* Hover contrast for the Add button picks up the tab color from its header background. */
.jobnotes-group[class*="jobnotes-group--"] .card-header .btn-outline-primary:hover {
    color: #2c3e50;
}

/* Job Notes cards stack full-width, one per row. Targets the card-column wrappers
   (the col-* holding a .jobnotes-group card) so the two-across col-lg-6 layout
   collapses to a single column, without editing each section's Razor. */
.jobnotes-palette .row > [class*="col-"]:has(> .jobnotes-group) {
    flex: 0 0 100%;
    max-width: 100%;
}

/* Job Notes field reflow: label-left / control-right rows (mimics New Job Email Row()).
   Scoped to .jobnotes-palette so it applies to BOTH Tabs and Single-page layouts and
   does NOT affect the Take-Off pages. Each field keeps its id="field-X" wrapper. */

/* Each field cell becomes its own full-width horizontal row. */
.jobnotes-palette .jobnotes-group .card-body > .row > [id^="field-"] {
    flex: 0 0 100%;
    max-width: 100%;
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
}

/* Left column: fixed 180px bold label. */
.jobnotes-palette .jobnotes-group .card-body > .row > [id^="field-"] > .form-label {
    flex: 0 0 180px;
    max-width: 180px;
    margin-bottom: 0;
    padding-top: 0.3rem;   /* baseline-align with form-control-sm text */
    font-weight: bold;
    color: inherit;        /* override muted .jobnotes-group .form-label */
    font-size: 0.8125rem;
    white-space: normal;
}

/* Right column: whatever control follows the label fills the rest. */
.jobnotes-palette .jobnotes-group .card-body > .row > [id^="field-"] > .form-label ~ * {
    flex: 1 1 auto;
    min-width: 0;          /* let input-group ($/%) shrink without overflow */
}

/* Bid overview: same label-left / control-right reflow, but with NO card chrome — the
   overview fields sit directly on the page, grouped under .overview-group sub-sections. */
.bid-overview-fields .overview-group-title {
    font-size: 0.72rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: #6c757d;
    padding-bottom: 0.25rem;
    margin-bottom: 0.4rem;
    border-bottom: 1px solid #e3e6ea;
}

.bid-overview-fields .row > [id^="field-"] {
    flex: 0 0 100%;
    max-width: 100%;
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
}

.bid-overview-fields .row > [id^="field-"] > .form-label {
    flex: 0 0 180px;
    max-width: 180px;
    margin-bottom: 0;
    padding-top: 0.3rem;
    font-weight: bold;
    color: inherit !important;   /* override the .text-muted on OverviewSection labels */
    font-size: 0.8125rem;
    white-space: normal;
}

.bid-overview-fields .row > [id^="field-"] > .form-label ~ * {
    flex: 1 1 auto;
    min-width: 0;
}

/* ===== Bid detail field search ===== */
.bid-field-search-results {
    position: absolute;
    z-index: 1050;
    top: 100%;
    left: 0;
    right: 0;
    max-height: 320px;
    overflow-y: auto;
    margin-top: 2px;
}

/* Brief highlight applied by BidFieldScroll.scrollToField when deep-linking to a field. */
@keyframes bidFieldFlash {
    0% { background-color: rgba(255, 193, 7, 0.55); }
    100% { background-color: transparent; }
}

.field-flash {
    animation: bidFieldFlash 1.6s ease-out;
    border-radius: 0.25rem;
}

/* ===== Bid detail density =====
   Cap the content width and pin it left so every bid-detail section page (take-off
   worksheet + Job Notes) leaves deliberate whitespace on the right, and tighten the
   field spacing so the information reads compactly instead of spread out. */
.bid-detail-content {
    max-width: 960px;
    margin-left: 0;
    margin-right: auto;
}

/* The Overview page adds a right-hand Related Jobs rail, so let it reclaim the width the
   960px cap otherwise leaves empty on the right. The left column keeps the readable width. */
.bid-detail-content:has(.bid-overview-columns) {
    max-width: 1320px;
}

/* ===== Bid detail rail =====
   The shell pairs every page with a rail in the space the width cap leaves empty on the right:
   the field search and menu, then Bid Summary, Required Fields and Notes. The rail belongs to the
   shell, so no page lays it out. */
.bid-detail-with-rail {
    display: flex;
    gap: 1rem;
    align-items: flex-start;
}

.bid-detail-with-rail > .bid-detail-content {
    flex: 1 1 auto;
    min-width: 0;
}

.bid-detail-rail {
    flex: 0 0 320px;
    position: sticky;
    top: 70px;
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    max-height: calc(100vh - 80px);
}

/* The toolbar stays out of the scrolling body so the search results drop over the page instead
   of being clipped at the rail's edge. */
.bid-rail-toolbar {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex: 0 0 auto;
}

.bid-field-search {
    flex: 1 1 auto;
    min-width: 0;
}

/* The cards scroll as one column, so a long blocker list or many notes move the rail rather than
   the page. */
.bid-rail-body {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
}

.bid-rail-body > .card {
    margin-bottom: 0.75rem;
}

.bid-rail-body > .card:last-child {
    margin-bottom: 0;
}

/* The status buttons and the round controls each stay on one line; the round name field
   gives up width first so a narrow viewport shrinks it instead of breaking the row. */
.bid-status-row {
    flex-wrap: nowrap;
    min-width: 0;
}

.bid-status-row .bid-round-name {
    width: 11rem;
    min-width: 5rem;
    flex-shrink: 1;
}

.bid-note {
    border-left: 3px solid #dee2e6;
    padding: 0 0 0 12px;
}

.bid-note-body {
    white-space: pre-wrap;
    word-break: break-word;
}

/* Below lg the rail stops being a column and reads as a panel under the content. */
@media (max-width: 991.98px) {
    .bid-detail-with-rail {
        display: block;
    }

    .bid-detail-rail {
        width: auto;
        position: static;
        max-height: none;
        margin-top: 1rem;
    }

    .bid-rail-body {
        overflow-y: visible;
    }
}

/* Tighten the Bootstrap row gutters used throughout the sections. */
.bid-detail-content .row.g-3 {
    --bs-gutter-y: 0.5rem;
    --bs-gutter-x: 0.75rem;
}

.bid-detail-content .row.g-2 {
    --bs-gutter-y: 0.35rem;
    --bs-gutter-x: 0.6rem;
}

/* Compact cards: smaller header/body padding and tighter spacing between cards. */
.bid-detail-content .card {
    margin-bottom: 0.75rem !important;
}

.bid-detail-content .card > .card-header {
    padding: 0.35rem 0.6rem;
}

.bid-detail-content .card > .card-body {
    padding: 0.6rem;
}

/* Smaller, tighter field labels everywhere in the bid detail. */
.bid-detail-content .form-label {
    font-size: 0.75rem;
    margin-bottom: 0.1rem;
}

/* ===== Currency input =====
   Money and percent fields size to their content rather than filling the grid column: the value
   is right-aligned, so a full-width field leaves the $ or % affix stranded at the far edge with a
   gap of empty box between it and the digits it labels. */
.currency-input {
    width: 100%;
}

.currency-input--dollars {
    max-width: 190px;
}

.currency-input--percent {
    max-width: 130px;
}

.currency-input .currency-input-field {
    font-variant-numeric: tabular-nums;
}

/* ===== Bid workspace: disclosure rows =====
   Relationship cards collapse to one line carrying their own state, so a stage reads as a short
   list of answers rather than a stack of headers and tables. */
.bid-row {
    background: var(--color-bg-surface);
    border: 1px solid var(--color-border);
    border-radius: 8px;
    margin-bottom: 8px;
    overflow: hidden;
}

.bid-row-head {
    width: 100%;
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 14px;
    background: none;
    border: 0;
    text-align: left;
    cursor: pointer;
}

.bid-row-head:hover {
    background: var(--color-bg-muted);
}

.bid-row-chevron {
    color: var(--color-text-muted);
    font-size: 0.7rem;
    transition: transform 0.15s ease-in-out;
    line-height: 1;
}

.bid-row.open .bid-row-chevron {
    transform: rotate(90deg);
}

.bid-row-name {
    font-size: 0.8125rem;
    font-weight: 600;
    min-width: 9rem;
}

.bid-row-state {
    font-size: 0.8125rem;
    color: var(--color-text-secondary);
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.bid-row-state--muted {
    color: var(--color-text-muted);
    font-style: italic;
}

.bid-row-state--attention {
    color: var(--color-warning);
    font-weight: 500;
}

.bid-row-badge {
    margin-left: auto;
    display: inline-flex;
    gap: 5px;
    align-items: center;
}

.bid-row-body {
    padding: 12px 14px;
    border-top: 1px solid var(--color-border-light);
    background: var(--color-bg-body);
}

/* ===== Bid workspace: stage body ===== */
.bid-stage-head {
    display: flex;
    align-items: baseline;
    gap: 10px;
    margin-bottom: 12px;
}

.bid-stage-head h5 {
    font-size: 1rem;
    margin: 0;
}

/* ===== Bid workspace: field grid =====
   A group is a twelve-track grid, so a team can span an entry across tracks and rows and leave a
   cell deliberately empty. An entry carrying no coordinates auto-flows into the gaps the positioned
   ones leave. */
.bid-grid {
    display: grid;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    /* A row is a third of a field's height, so a gap between groupings can be smaller than a field.
       An ordinary field spans three rows: 3 x 1.25rem plus the two 0.5rem gaps between them comes to
       the 4.75rem a field occupies.

       The track is a fixed height, not a minmax with an auto max. An auto max lets a cell's content
       stretch every row it spans, which would make a row taller than a third of a field and leave
       the grid unable to express a gap smaller than one. */
    grid-auto-rows: var(--bid-grid-row, 1.25rem);
    grid-auto-flow: row dense;
    column-gap: 0.75rem;
    row-gap: 0.5rem;
}

/* A field fills the cell it was given, so a taller span shows as more room. min-height leaves a
   list or grid free to grow past its span, which a fixed height on a fixed row track would clip. */
.bid-grid-cell {
    min-height: 100%;
}

.bid-grid-cell > * {
    min-height: 100%;
}

.bid-grid-cell textarea {
    height: 100%;
    resize: none;
}

/* A bare 1fr track carries an implicit min-width:auto. A long select or input group refuses to
   shrink below that, and overflows the card. */
.bid-grid-cell {
    min-width: 0;
}

/* An entry taller than the cell it was given paints above what follows it. Grid paints in DOM order,
   so without this an entry that outgrows its span is covered by every entry placed after it. No
   overflow rule belongs here: it would clip the dropdown of a select inside a cell. */
.bid-grid-cell {
    z-index: 0;
}

.bid-grid-cell:hover,
.bid-grid-cell:focus-within {
    z-index: 1;
}

/* A block whose height follows the bid's own answers, holding the width of the grid it sits between.
   The margin matches the grid's row gap, so a band reads as one more row of the group. */
.bid-grid-band {
    margin-bottom: 0.5rem;
}

.bid-grid-band:last-child {
    margin-bottom: 0;
}

/* Half the tracks per entry below lg, so a quarter-width field is readable without becoming a
   full-width one. An entry already spanning most of the grid keeps its width.
   The coordinates an entry carries are inline styles, which only !important can override. */
@media (max-width: 991.98px) {
    .bid-grid-cell {
        grid-row: auto !important;
    }

    .bid-grid-cell:not(.bid-grid-cell--wide) {
        grid-column: auto / span 6 !important;
    }

    .bid-grid-cell--wide {
        grid-column: 1 / -1 !important;
    }
}

/* One entry per row on a phone: a layout arranged for a desktop grid says nothing at this width. */
@media (max-width: 767.98px) {
    .bid-grid {
        grid-template-columns: 1fr;
    }

    .bid-grid-cell,
    .bid-grid-cell--wide {
        grid-column: 1 / -1 !important;
        grid-row: auto !important;
    }
}

/* ===== Bid workspace: form edit mode ===== */

.bid-form-edit-banner {
    position: sticky;
    top: 0;
    z-index: 20;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
    padding: 8px 12px;
    margin-bottom: 10px;
    border-radius: 6px;
    background: color-mix(in srgb, var(--color-primary) 12%, var(--color-surface));
    border: 1px solid color-mix(in srgb, var(--color-primary) 40%, transparent);
    font-size: 0.85rem;
}

.bid-form-edit-banner.previewing {
    background: color-mix(in srgb, #d97706 14%, var(--color-surface));
    border-color: color-mix(in srgb, #d97706 45%, transparent);
}

.bid-form-edit-banner__note {
    display: block;
    color: var(--color-text-muted);
    font-size: 0.78rem;
}

.bid-form-edit-banner__actions {
    display: flex;
    gap: 8px;
}

.bid-form-tile {
    position: relative;
    height: 100%;
    padding: 4px 4px 4px 14px;
    border-radius: 5px;
    border: 1px dashed var(--color-border);
    transition: border-color 0.12s, box-shadow 0.12s;
}

.bid-form-tile:hover {
    border-color: var(--color-primary);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-primary) 18%, transparent);
}

/* Lifted out of the grid flow and following the pointer, so the row it will land in reads clearly. */
.bid-form-tile.dragging {
    opacity: 0.9;
    border-color: var(--color-primary);
    border-style: dashed;
    box-shadow: 0 6px 16px rgba(0, 0, 0, 0.18);
}

.bid-form-tile.resizing {
    border-color: var(--color-primary);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-primary) 25%, transparent);
}

/* The control underneath shows what the arrangement will look like. inert takes it out of the tab
   order and the accessibility tree, so a keyboard user cannot land inside a field being arranged. */
.bid-form-tile__content {
    pointer-events: none;
    user-select: none;
}

.bid-form-tile__shield {
    position: absolute;
    inset: 0;
    z-index: 2;
    cursor: grab;
    background: transparent;
    border-radius: 5px;
}

.bid-form-tile.dragging {
    opacity: 0.75;
    z-index: 5;
}

.bid-form-tile.dragging .bid-form-tile__shield {
    cursor: grabbing;
}

/* A permanent grab strip down the left edge, so every tile shows where to take hold of it. */
.bid-form-tile__grip {
    position: absolute;
    top: 0;
    left: 0;
    bottom: 0;
    z-index: 3;
    width: 12px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 5px 0 0 5px;
    color: var(--color-text-muted);
    font-size: 0.7rem;
    pointer-events: none;
}

.bid-form-tile:hover .bid-form-tile__grip {
    background: color-mix(in srgb, var(--color-primary) 20%, transparent);
    color: var(--color-primary);
}

.bid-form-tile__required {
    position: absolute;
    top: 2px;
    right: 4px;
    z-index: 3;
    font-size: 0.75rem;
    color: var(--bs-danger);
    font-weight: 700;
    pointer-events: none;
}

/* Sits above the shield, so a grab on an edge resizes the tile and does not start a move. */
.bid-form-tile__resize {
    position: absolute;
    z-index: 4;
}

.bid-form-tile__resize::after {
    content: "";
    position: absolute;
    border-radius: 2px;
    background: transparent;
}

.bid-form-tile:hover .bid-form-tile__resize::after {
    background: var(--color-primary);
}

.bid-form-tile__resize--e {
    top: 25%;
    right: 0;
    width: 10px;
    height: 50%;
    cursor: ew-resize;
}

.bid-form-tile__resize--e::after {
    top: 25%;
    bottom: 25%;
    left: 4px;
    width: 3px;
}

.bid-form-tile__resize--s {
    left: 25%;
    bottom: 0;
    width: 50%;
    height: 10px;
    cursor: ns-resize;
}

.bid-form-tile__resize--s::after {
    left: 25%;
    right: 25%;
    top: 4px;
    height: 3px;
}

.bid-form-tile__resize--se {
    right: 0;
    bottom: 0;
    width: 14px;
    height: 14px;
    cursor: nwse-resize;
}

.bid-form-tile__resize--se::after {
    right: 3px;
    bottom: 3px;
    width: 7px;
    height: 7px;
    border-radius: 0 0 3px 0;
}

/* An entry the bid's answers do not currently reveal still holds its place on the form, and is
   arranged like any other. Hatched and dimmed, naming the answer that shows it, so the tile reads as
   a field that is off for this bid and not as one that failed to draw. */
.bid-grid-cell--conditional .bid-form-tile {
    background: repeating-linear-gradient(45deg,
        transparent, transparent 6px,
        color-mix(in srgb, var(--color-text-muted) 7%, transparent) 6px,
        color-mix(in srgb, var(--color-text-muted) 7%, transparent) 12px);
}

.bid-conditional-stub {
    display: flex;
    flex-direction: column;
    justify-content: center;
    height: 100%;
    min-width: 0;
    padding: 2px 4px;
    overflow: hidden;
}

.bid-conditional-stub__label,
.bid-conditional-stub__hint {
    color: var(--color-text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.bid-conditional-stub__label {
    font-size: 0.8rem;
    font-weight: 600;
}

.bid-conditional-stub__hint {
    font-size: 0.7rem;
    font-style: italic;
}

/* A drag reads the pointer from the document, so nothing under it should take a selection. */
body.bid-form-dragging {
    user-select: none;
    cursor: grabbing;
}

/* Everything not being dragged settles into its new cell, so the shift itself is what reads. */
body.bid-form-dragging .bid-grid-cell {
    transition: grid-column 0.12s ease, grid-row 0.12s ease;
}

.bid-stage-foot {
    display: flex;
    align-items: center;
    gap: 12px;
    padding-top: 12px;
    margin-top: 4px;
    border-top: 1px solid var(--color-border-light);
}

.bid-stage-foot .mid {
    flex: 1;
    text-align: center;
    font-size: 0.75rem;
    color: var(--color-text-muted);
}

/* ===== Bid workspace: readiness =====
   The Required Fields card in the rail. Its header is a button so a cleared card opens onto the
   per-page counts; the button is disabled while anything blocks, which is what pins it open. */
.bid-readiness-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    width: 100%;
    text-align: left;
    border: 0;
    border-bottom: 1px solid var(--color-border);
    padding: 0.35rem 0.6rem;
    cursor: pointer;
}

.bid-readiness-head:disabled {
    cursor: default;
}

.bid-readiness-title {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--color-text-primary);
}

.bid-readiness-bar {
    width: 100%;
    height: 7px;
    border-radius: 99px;
    background: var(--color-bg-muted);
    overflow: hidden;
}

.bid-readiness-fill {
    display: block;
    height: 100%;
    background: var(--color-primary);
    transition: width 0.25s ease-in-out;
}

/* One blocker per row: at 320px a wrapping pill list puts most pills on a line of their own
   anyway, and the card is read as a to-do list. */
.bid-blockers {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin: 8px 0 0;
    padding: 0;
    list-style: none;
}

.bid-blocker {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    text-align: left;
    font-size: 0.75rem;
    background: var(--color-bg-surface);
    border: 1px solid var(--color-border);
    color: var(--color-text-secondary);
    border-radius: 6px;
    padding: 4px 8px;
    cursor: pointer;
    line-height: 1.35;
}

.bid-blocker:hover {
    border-color: var(--color-primary);
    color: var(--color-primary-hover);
}

.bid-blocker-dot {
    width: 6px;
    height: 6px;
    border-radius: 99px;
    background: var(--color-error);
    flex: 0 0 auto;
}

.bid-blocker-text {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.bid-blocker-page {
    font-size: 0.6875rem;
    color: var(--color-text-muted);
}

/* A cleared card opens onto how much of each page is filled. */
.bid-readiness-pages {
    margin: 0;
    padding: 0;
    list-style: none;
}

.bid-readiness-page {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 8px;
    font-size: 0.75rem;
    padding: 3px 0;
}

.bid-readiness-page-name {
    color: var(--color-text-secondary);
}

.bid-readiness-page-count {
    color: var(--color-text-muted);
    font-variant-numeric: tabular-nums;
}

/* Per-stage progress in the bid nav. The .nav-menu prefix is needed to beat the shared
   `.nav-menu .nav-item span` left margin, which would otherwise pull the count off the right edge. */
.nav-menu .nav-item span.nav-stage-count {
    margin-left: auto;
    padding-left: 0.5rem;
    font-size: 0.6875rem;
    font-weight: 500;
    font-variant-numeric: tabular-nums;
    color: var(--color-text-muted);
}

.nav-menu .nav-item span.nav-stage-count--blocking {
    color: var(--color-error);
    font-weight: 600;
}

/* ===== Bid workspace: bid summary =====
   Bid-level facts that belong to no single page, as one labelled row each inside the rail card.
   The card supplies the surface and border, so the list itself carries only its separators. */
.bid-strip {
    display: flex;
    flex-direction: column;
}

.bid-strip-cell {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 8px;
    padding: 5px 0;
    border-top: 1px solid var(--color-border-light);
}

.bid-strip-cell:first-child {
    border-top: 0;
    padding-top: 0;
}

.bid-strip-label {
    font-size: 0.625rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    font-weight: 600;
    color: var(--color-text-muted);
    line-height: 1.4;
}

.bid-strip-value-group {
    display: flex;
    align-items: baseline;
    gap: 8px;
    flex-wrap: wrap;
}

.bid-strip-value {
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--color-text-primary);
    text-align: left;
    line-height: 1.4;
    background: none;
    border: 0;
    padding: 0;
}

.bid-strip-value--action {
    cursor: pointer;
    border-bottom: 1px dashed transparent;
}

.bid-strip-value--action:hover {
    color: var(--color-primary-hover);
    border-bottom-color: var(--color-primary);
}

.bid-strip-value--muted {
    font-weight: 500;
    font-style: italic;
    color: var(--color-text-muted);
}

.bid-strip-link {
    font-size: 0.6875rem;
    color: var(--color-text-link);
    background: none;
    border: 0;
    padding: 0;
    cursor: pointer;
}

.bid-strip-link:hover {
    color: var(--color-text-link-hover);
    text-decoration: underline;
}

/* ===== Bid workspace: a closed pricing round =====
   The header is a button so the whole row opens the round, which needs the browser's own button
   chrome cleared before it sits inside a card. */
.bid-round-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    width: 100%;
    text-align: left;
    border: 0;
    border-bottom: 1px solid var(--color-border);
    padding: 0.35rem 0.6rem;
    cursor: pointer;
}

.bid-round-title {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 0.8125rem;
    color: var(--color-text-primary);
}

.bid-round-facts {
    display: flex;
    align-items: baseline;
    gap: 10px;
    font-size: 0.75rem;
    font-variant-numeric: tabular-nums;
}

.bid-round-group {
    margin-top: 10px;
}

.bid-round-group-name {
    font-size: 0.6875rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    font-weight: 600;
    color: var(--color-text-muted);
    margin-bottom: 3px;
}

/* ===== Bid workspace: requesting contractors =====
   One card per GC on Contractor Info. The primary card is tinted and takes the accent border, so
   the contractor the bid is scoped to is findable without reading every badge. */
.bid-requestor-card {
    border: 1px solid var(--color-border);
}

.bid-requestor-card--primary {
    border-color: var(--color-primary);
    background: color-mix(in srgb, var(--color-primary) 4%, var(--color-bg-surface));
}

/* Stage body: the "nothing left here" line inside the needed-to-open-the-job card. */
.bid-stage-clear {
    font-size: 0.8125rem;
    color: var(--color-success);
    margin-bottom: 8px;
}

.bid-stage-rows,
.bid-stage-optional {
    margin-top: 12px;
}

/* The stage's own fields, above the disclosure rows and folds. */
.bid-stage-body {
    margin-bottom: 4px;
}

@media (max-width: 575.98px) {
    .bid-strip-cell {
        flex: 1 1 100%;
        border-left: 0;
        border-top: 1px solid var(--color-border-light);
    }

    .bid-strip-cell:first-child {
        border-top: 0;
    }
}

/* ===== Bid workspace: scenario value hint =====
   Sits under the field it fills, so the Estimating Edge figure and the input it would go into read
   as one thing rather than a separate screen. */
.scenario-hint {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
    margin-top: 3px;
    font-size: 0.6875rem;
    line-height: 1.5;
}

.scenario-hint-label {
    color: var(--color-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    font-weight: 600;
}

.scenario-hint-value {
    color: var(--color-text-secondary);
    font-variant-numeric: tabular-nums;
}

.scenario-hint-apply,
.scenario-hint-toggle {
    background: none;
    border: 0;
    padding: 0;
    cursor: pointer;
    font-size: 0.6875rem;
    color: var(--color-text-link);
    text-decoration: none;
}

.scenario-hint-apply:hover,
.scenario-hint-toggle:hover {
    color: var(--color-text-link-hover);
    text-decoration: underline;
}

.scenario-hint-toggle {
    color: var(--color-text-muted);
}

/* ===== Bid handoff: the run from bid to job =====
   Three steps on one page rather than three destinations, because the project link that gates the
   later half is created in the middle of the run. */
.handoff-steps {
    display: flex;
    gap: 6px;
    list-style: none;
    padding: 0;
    margin: 0 0 16px;
    flex-wrap: wrap;
}

.handoff-steps li {
    display: flex;
    align-items: center;
    gap: 7px;
    padding: 6px 13px 6px 7px;
    border: 1px solid var(--color-border);
    border-radius: 99px;
    font-size: 0.78125rem;
    background: var(--color-bg-surface);
}

.handoff-step-num {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.25rem;
    height: 1.25rem;
    border-radius: 99px;
    background: var(--color-bg-muted);
    color: var(--color-text-muted);
    font-size: 0.6875rem;
    font-weight: 700;
    flex: 0 0 auto;
}

.handoff-steps li.done {
    border-color: color-mix(in srgb, var(--color-success) 45%, transparent);
}

.handoff-steps li.done .handoff-step-num {
    background: var(--color-success);
    color: var(--color-text-inverse);
}

.handoff-steps li.current {
    border-color: var(--color-primary);
    box-shadow: 0 0 0 3px rgba(var(--color-primary-rgb), 0.1);
}

.handoff-steps li.current .handoff-step-num {
    background: var(--color-primary);
    color: var(--color-text-inverse);
}

.handoff-steps li.waiting {
    color: var(--color-text-muted);
}

/* ===== Bid workspace: field groups =====
   One group of a page's fields. The head carries the group name and how much of it is answered;
   the body is always drawn, so a deep link can scroll to any field and browser find reaches all of
   them. */
.bid-group-card {
    background: var(--color-bg-surface);
    border: 1px solid var(--color-border);
    border-radius: 8px;
    margin-bottom: 8px;
    overflow: hidden;
}

.bid-group-head {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 14px;
}

.bid-group-name {
    font-size: 0.8125rem;
    font-weight: 600;
    flex: 1;
}

.bid-group-count {
    font-size: 0.6875rem;
    color: var(--color-text-muted);
    font-variant-numeric: tabular-nums;
}

.bid-group-body {
    padding: 12px 14px;
    border-top: 1px solid var(--color-border-light);
    background: var(--color-bg-body);
}
