/* /Components/Layout/MainLayout.razor.rz.scp.css */
/* MainLayout — app chrome. Depends on tokens defined in
   /wwwroot/css/theme.css. Do not introduce hard-coded hex
   values here; status colors flow from --status-* and brand
   colors from --brand-*. */

.web-app-shell[b-rcrf517nbc] {
    min-height: 100vh;
    background: var(--bg);
    color: var(--text);
}

.web-app-header[b-rcrf517nbc] {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 0.7rem;
    padding: 0.34rem 0.85rem;
    background:
        linear-gradient(180deg, color-mix(in oklab, var(--brand-sea-soft) 55%, var(--surface)) 0%, var(--surface) 92%),
        var(--surface);
    border-bottom: 1px solid var(--border);
    box-shadow: var(--shadow-sm);
    position: relative;
}

/* Thin brand stripe along the bottom of the header — anchors
   the eye at the top of every page. Gradient draws from the
   primary sea blue through the sky-glow highlight. */
.web-app-header[b-rcrf517nbc]::after {
    content: "";
    position: absolute;
    left: 0; right: 0; bottom: 0;
    height: 2px;
    background: linear-gradient(90deg,
        var(--brand-sea) 0%,
        var(--brand-glow) 50%,
        var(--brand-sea) 100%);
}

.web-app-brand[b-rcrf517nbc] {
    display: flex;
    align-items: center;
    gap: 0.45rem;
}

.web-app-brand__mark[b-rcrf517nbc] {
    width: 1.55rem;
    height: 1.55rem;
    flex: 0 0 auto;
    display: grid;
    place-items: center;
    border-radius: var(--radius-sm);
    background: color-mix(in oklab, var(--brand-sea-soft) 80%, var(--surface));
    border: 1px solid color-mix(in oklab, var(--brand-sea) 22%, var(--border));
    box-shadow: inset 0 0 12px color-mix(in oklab, var(--brand-glow) 18%, transparent);
}
.web-app-brand__mark img[b-rcrf517nbc] {
    width: 100%;
    height: 100%;
    object-fit: contain;
    display: block;
}

.web-app-brand__text[b-rcrf517nbc] {
    display: flex;
    flex-direction: column;
    gap: 0.05rem;
}

.web-app-brand__name[b-rcrf517nbc] {
    font-family: var(--font-display);
    color: var(--text);
    text-decoration: none;
    font-size: 0.9rem;
    font-weight: 800;
    line-height: 1.05;
    letter-spacing: -0.01em;
}

.web-app-brand__tagline[b-rcrf517nbc] {
    margin: 0;
    color: var(--text-muted);
    font-size: 0.6rem;
    line-height: 1.1;
}

.web-app-actions[b-rcrf517nbc] {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    flex-wrap: wrap;
}

.web-header-btn[b-rcrf517nbc] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.34rem;
    min-height: 1.8rem;
    padding: 0.28rem 0.55rem;
    border-radius: var(--radius-sm);
    border: 1px solid var(--border-strong);
    background: var(--surface);
    color: var(--text);
    text-decoration: none;
    font-weight: 600;
    font-size: 0.72rem;
    transition: border-color 120ms ease, background 120ms ease, transform 120ms ease;
}

.web-header-btn__icon[b-rcrf517nbc] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 0.82rem;
    height: 0.82rem;
    font-size: 0.74rem;
    line-height: 1;
}

.web-header-btn:hover[b-rcrf517nbc] {
    border-color: color-mix(in oklab, var(--brand-sea) 40%, var(--border-strong));
    background: color-mix(in oklab, var(--brand-sea-soft) 55%, var(--surface));
    color: var(--text);
    transform: translateY(-1px);
}

.web-header-btn--primary[b-rcrf517nbc] {
    background: linear-gradient(180deg, var(--brand-sea) 0%, var(--brand-sea-ink) 100%);
    color: #fff;
    border-color: transparent;
    box-shadow: var(--shadow-sm);
}

.web-header-btn--primary:hover[b-rcrf517nbc] {
    color: #fff;
    filter: brightness(1.05);
    box-shadow: var(--shadow-md);
    background: linear-gradient(180deg, var(--brand-sea) 0%, var(--brand-sea-ink) 100%);
}

.web-header-btn--ghost[b-rcrf517nbc] {
    background: color-mix(in oklab, var(--surface) 82%, var(--bg));
}

/* Theme toggle — icon-only button that flips data-theme via
   a small client script (see MainLayout.razor). */
.web-theme-toggle[b-rcrf517nbc] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.8rem;
    height: 1.8rem;
    padding: 0;
    border-radius: 50%;
    border: 1px solid var(--border-strong);
    background: var(--surface);
    color: var(--text-muted);
    cursor: pointer;
    transition: color 120ms ease, border-color 120ms ease, background 120ms ease;
}
.web-theme-toggle:hover[b-rcrf517nbc] {
    color: var(--brand-sea);
    border-color: color-mix(in oklab, var(--brand-sea) 45%, var(--border-strong));
    background: color-mix(in oklab, var(--brand-sea-soft) 55%, var(--surface));
}
.web-theme-toggle svg[b-rcrf517nbc] {
    width: 0.96rem;
    height: 0.96rem;
}

.web-utility-menu[b-rcrf517nbc] {
    position: relative;
}

.web-utility-menu[open][b-rcrf517nbc] {
    z-index: 30;
}

.web-utility-toggle[b-rcrf517nbc] {
    list-style: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.8rem;
    height: 1.8rem;
    padding: 0;
    border-radius: 50%;
    border: 1px solid var(--border-strong);
    background: var(--surface);
    color: var(--text-muted);
    cursor: pointer;
    transition: color 120ms ease, border-color 120ms ease, background 120ms ease;
}

.web-utility-toggle[b-rcrf517nbc]::-webkit-details-marker {
    display: none;
}

.web-utility-toggle:hover[b-rcrf517nbc],
.web-utility-menu[open] > .web-utility-toggle[b-rcrf517nbc] {
    color: var(--brand-sea);
    border-color: color-mix(in oklab, var(--brand-sea) 45%, var(--border-strong));
    background: color-mix(in oklab, var(--brand-sea-soft) 55%, var(--surface));
}

.web-utility-toggle svg[b-rcrf517nbc] {
    width: 0.94rem;
    height: 0.94rem;
}

.web-utility-popover[b-rcrf517nbc] {
    position: absolute;
    right: 0;
    top: calc(100% + 0.45rem);
    min-width: 10rem;
    padding: 0.4rem;
    border-radius: var(--radius-md);
    border: 1px solid var(--border);
    background: var(--surface-raised);
    box-shadow: var(--shadow-md);
    display: grid;
    gap: 0.2rem;
}

.web-utility-link[b-rcrf517nbc] {
    display: flex;
    align-items: center;
    min-height: 2rem;
    padding: 0.36rem 0.55rem;
    border-radius: var(--radius-sm);
    color: var(--text);
    text-decoration: none;
    font-size: 0.78rem;
    font-weight: 600;
}

.web-utility-link:hover[b-rcrf517nbc] {
    background: color-mix(in oklab, var(--brand-sea-soft) 52%, var(--surface));
    color: var(--brand-sea);
}

.web-utility-divider[b-rcrf517nbc] {
    /* Separates the "tool" section (Reports, Exports) from the
       "configuration" section (Settings, Company, Rooms, ...). Kept
       quiet so it reads as grouping rather than competing for
       attention. */
    margin: 0.28rem 0.15rem;
    border: none;
    border-top: 1px solid var(--border);
    opacity: 0.6;
}

.web-auth-chip[b-rcrf517nbc] {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    min-height: 1.8rem;
    padding: 0.2rem 0.55rem;
    border-radius: 999px;
    border: 1px solid var(--border-strong);
    background: color-mix(in oklab, var(--surface) 88%, var(--bg));
    font-size: 0.72rem;
    font-weight: 700;
}

.web-auth-chip form[b-rcrf517nbc] {
    margin: 0;
}

/* +New split button (PBI #15224). The <summary> needs the primary
   button look — .web-header-btn--primary supplies background + color,
   we just suppress the native disclosure marker and add caret spacing
   so the dropdown affordance reads clearly. */
.web-split-toggle[b-rcrf517nbc] {
    list-style: none;
    cursor: pointer;
}

.web-split-toggle[b-rcrf517nbc]::-webkit-details-marker {
    display: none;
}

.web-split-caret[b-rcrf517nbc] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 0.7rem;
    height: 0.7rem;
    margin-left: 0.15rem;
    transition: transform 120ms ease;
}

.web-split-caret svg[b-rcrf517nbc] {
    width: 100%;
    height: 100%;
}

.web-utility-menu[open] > summary .web-split-caret[b-rcrf517nbc] {
    transform: rotate(180deg);
}

/* Auth-menu popover (PBI #15224). The <summary> *is* the chip — we
   need to suppress the native marker and let .web-auth-chip carry
   the visual styling. */
.web-auth-menu > summary.web-auth-chip[b-rcrf517nbc] {
    list-style: none;
    cursor: pointer;
}

.web-auth-menu > summary.web-auth-chip[b-rcrf517nbc]::-webkit-details-marker {
    display: none;
}

.web-auth-menu[open] > summary.web-auth-chip[b-rcrf517nbc] {
    border-color: color-mix(in oklab, var(--brand-sea) 45%, var(--border-strong));
    background: color-mix(in oklab, var(--brand-sea-soft) 55%, var(--surface));
    color: var(--brand-sea);
}

.web-auth-menu__form[b-rcrf517nbc] {
    margin: 0;
    display: contents;
}

/* Sign-out button as a popover row — borrows .web-utility-link
   shape, just strips the native <button> chrome so it sits flush
   with the other links in the popover. */
.web-auth-menu__signout[b-rcrf517nbc] {
    border: 0;
    background: transparent;
    width: 100%;
    text-align: left;
    font: inherit;
    cursor: pointer;
}

.web-content-shell[b-rcrf517nbc] {
    padding: 1rem 1rem 3rem;
    max-width: 1600px;
    margin: 0 auto;
}

/* PBI #15233 — shared breadcrumb strip rendered by MainLayout.
   Detail pages (JobDetail/ClientDetail/ProductDetail) populate the
   trail via BreadcrumbsState.Set(...); this replaces the three
   different ad-hoc "Back to ..." button styles those pages each
   invented. List pages (no trail set) render nothing. */
[b-rcrf517nbc] .app-breadcrumbs {
    margin: 0 0 0.85rem;
    font-size: 0.78rem;
    line-height: 1.2;
}

[b-rcrf517nbc] .app-breadcrumbs__list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.25rem 0.35rem;
}

[b-rcrf517nbc] .app-breadcrumbs__item {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    color: var(--text-muted);
}

[b-rcrf517nbc] .app-breadcrumbs__link {
    color: var(--text-muted);
    text-decoration: none;
    border-radius: var(--radius-sm);
    padding: 0.1rem 0.25rem;
    transition: color 120ms ease, background 120ms ease;
}

[b-rcrf517nbc] .app-breadcrumbs__link:hover,
[b-rcrf517nbc] .app-breadcrumbs__link:focus-visible {
    color: var(--brand-sea);
    background: color-mix(in oklab, var(--brand-sea-soft) 55%, var(--surface));
    outline: none;
}

[b-rcrf517nbc] .app-breadcrumbs__sep {
    color: var(--border-strong);
    user-select: none;
}

[b-rcrf517nbc] .app-breadcrumbs__current {
    color: var(--text);
    font-weight: 600;
    padding: 0.1rem 0.25rem;
}

.web-legacy-toolbar[b-rcrf517nbc] {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
    padding: 0.35rem 1rem 0.45rem;
    background: color-mix(in oklab, var(--surface) 88%, var(--bg));
    border-bottom: 1px solid var(--border);
}

.web-legacy-link[b-rcrf517nbc] {
    display: inline-flex;
    align-items: center;
    min-height: 1.75rem;
    padding: 0.24rem 0.62rem;
    border-radius: 999px;
    border: 1px solid color-mix(in oklab, var(--border-strong) 78%, transparent);
    background: color-mix(in oklab, var(--surface) 92%, var(--bg));
    color: var(--text-muted);
    text-decoration: none;
    font-size: 0.75rem;
    font-weight: 700;
    line-height: 1;
    letter-spacing: 0.01em;
    transition: border-color 120ms ease, color 120ms ease, background 120ms ease, transform 120ms ease;
}

.web-legacy-link:hover[b-rcrf517nbc] {
    color: var(--brand-sea);
    border-color: color-mix(in oklab, var(--brand-sea) 36%, var(--border));
    background: color-mix(in oklab, var(--brand-sea-soft) 50%, var(--surface));
    transform: translateY(-1px);
}

.web-legacy-link.active[b-rcrf517nbc] {
    color: var(--text-inverse);
    border-color: transparent;
    background: linear-gradient(180deg, var(--brand-sea) 0%, var(--brand-sea-ink) 100%);
    box-shadow: var(--shadow-sm);
}

#blazor-error-ui[b-rcrf517nbc] {
    color-scheme: light only;
    background: var(--status-warning-soft);
    color: var(--status-warning-ink);
    bottom: 0;
    box-shadow: 0 -1px 12px rgba(0, 0, 0, 0.2);
    box-sizing: border-box;
    display: none;
    left: 0;
    padding: 0.75rem 1.25rem 0.85rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}

#blazor-error-ui .dismiss[b-rcrf517nbc] {
    cursor: pointer;
    position: absolute;
    right: 0.75rem;
    top: 0.5rem;
}

/* =============================================================
   Responsive app chrome
   -------------------------------------------------------------
   Stops come from the --bp-* scale in theme.css: 1024 (tablet
   landscape), 768 (tablet portrait), 640 (phone). The old single
   720px carve sat in the dead zone between a phone and an iPad —
   it fired on neither, so an iPad in portrait got the full
   desktop header and a phone got a header that stacked one
   breakpoint too late.

   Desktop rendering above 1024px is deliberately untouched.
   ============================================================= */

/* --- tablet landscape and below (1024px) ------------------------ */
@media (max-width: 1024px) {
    /* Vertical space is the scarce resource on a tablet: the grid
       is what the user came for, the chrome is not. Pin the header
       so it survives scrolling and let everything else move under
       it. Only the header is sticky — making the module nav sticky
       too would need a hard-coded header height, and the header
       height changes with the auth chip. */
    .web-app-header[b-rcrf517nbc] {
        position: sticky;
        top: 0;
        z-index: 20;
        padding-top: calc(0.34rem + var(--safe-t));
    }

    .web-content-shell[b-rcrf517nbc] {
        padding: 0.85rem 0.85rem calc(3rem + var(--safe-b));
    }

    /* The legacy pill toolbar wraps to three rows at this width and
       eats the top third of the screen. One swipeable row instead —
       same treatment NavMenu already uses for the module tabs. */
    .web-legacy-toolbar[b-rcrf517nbc] {
        flex-wrap: nowrap;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        scrollbar-width: none;
    }

    .web-legacy-toolbar[b-rcrf517nbc]::-webkit-scrollbar {
        display: none;
    }

    .web-legacy-link[b-rcrf517nbc] {
        flex: 0 0 auto;
    }
}

/* --- tablet portrait and below (768px) -------------------------- */
@media (max-width: 768px) {
    .web-app-header[b-rcrf517nbc] {
        gap: 0.5rem;
        padding-left: 0.6rem;
        padding-right: 0.6rem;
    }

    /* The tagline is the first thing to go — it is decoration, and
       the brand name plus the action cluster both need the width. */
    .web-app-brand__tagline[b-rcrf517nbc] {
        display: none;
    }

    .web-app-actions[b-rcrf517nbc] {
        flex-wrap: nowrap;
    }

    /* Anchored right so the popover cannot hang off the edge of a
       768px viewport the way a fixed 10rem min-width would. */
    .web-utility-popover[b-rcrf517nbc] {
        min-width: 0;
        width: max-content;
        max-width: min(16rem, calc(100vw - 1.2rem));
    }

    .web-content-shell[b-rcrf517nbc] {
        padding: 0.7rem 0.7rem calc(2.5rem + var(--safe-b));
    }

    /* A three-level trail wraps to two lines and pushes the page
       title below the fold. Keep the trail on one line and let the
       leading crumbs ellipsis instead. */
    [b-rcrf517nbc] .app-breadcrumbs__list {
        flex-wrap: nowrap;
        overflow: hidden;
    }

    [b-rcrf517nbc] .app-breadcrumbs__link {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        max-width: 8rem;
    }

    [b-rcrf517nbc] .app-breadcrumbs__current {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }
}

/* --- phone (640px) ---------------------------------------------- */
@media (max-width: 640px) {
    /* Below this the brand and the action cluster genuinely do not
       share a line, so stack them and give the actions the full
       width to spread across. */
    .web-app-header[b-rcrf517nbc] {
        flex-direction: column;
        align-items: stretch;
    }

    .web-app-actions[b-rcrf517nbc] {
        justify-content: space-between;
        flex-wrap: wrap;
    }

    .web-content-shell[b-rcrf517nbc] {
        padding: 0.6rem 0.6rem calc(2.25rem + var(--safe-b));
    }
}

/* --- touch sizing ----------------------------------------------- */
/* Keyed on the input device, not the width: a 1024px iPad and a
   1440px touch laptop both need 44px targets, and a 700px browser
   window on a desktop does not. Values come from --control-h in
   theme.css, which flips to --tap-min under `pointer: coarse`. */
@media (pointer: coarse) {
    .web-header-btn[b-rcrf517nbc],
    .web-auth-chip[b-rcrf517nbc] {
        min-height: var(--control-h);
        padding-inline: 0.7rem;
    }

    .web-theme-toggle[b-rcrf517nbc],
    .web-utility-toggle[b-rcrf517nbc] {
        width: var(--control-h);
        height: var(--control-h);
    }

    .web-utility-link[b-rcrf517nbc] {
        min-height: var(--control-h);
    }

    .web-legacy-link[b-rcrf517nbc] {
        min-height: var(--control-h);
        padding-inline: 0.85rem;
    }

    /* Hover borders latch on after a tap and leave the last-touched
       control looking permanently focused. */
    .web-header-btn:hover[b-rcrf517nbc],
    .web-legacy-link:hover[b-rcrf517nbc] {
        transform: none;
    }
}
/* /Components/Layout/NavMenu.razor.rz.scp.css */
/* NavMenu — tokenised. Active link now uses the brand-sea
   gradient instead of flat ink black; non-active links are
   muted until hover so the current page reads as the focal
   point. */

.web-module-nav[b-1tvai779q2] {
    display: flex;
    gap: 0.25rem;
    flex-wrap: wrap;
    padding: 0.55rem 1rem 0.65rem;
    background: var(--surface);
    border-bottom: 1px solid var(--border);
}

.web-module-nav[b-1tvai779q2]  .web-module-link {
    display: inline-flex;
    align-items: center;
    min-height: 1.85rem;
    padding: 0.28rem 0.78rem;
    border-radius: 999px;
    color: var(--text-muted);
    text-decoration: none;
    font-weight: 600;
    font-size: 0.8rem;
    line-height: 1;
    border: 1px solid transparent;
    transition: color 120ms ease, background 120ms ease, border-color 120ms ease;
}

.web-module-nav[b-1tvai779q2]  .web-module-link:hover {
    color: var(--brand-sea);
    background: color-mix(in oklab, var(--brand-sea-soft) 55%, var(--surface));
    border-color: color-mix(in oklab, var(--brand-sea) 22%, var(--border));
}

.web-module-nav[b-1tvai779q2]  a.active,
.web-module-nav[b-1tvai779q2]  a.active:hover,
.web-module-nav[b-1tvai779q2]  a.active:focus-visible {
    /* Single rule for active + active-hover + active-focus so the
       base .web-module-link:hover background can never blank out
       the gradient underneath the white text. */
    background: linear-gradient(180deg, var(--brand-sea) 0%, var(--brand-sea-ink) 100%);
    color: #ffffff;
    border-color: transparent;
    box-shadow: var(--shadow-sm);
}

.web-module-nav[b-1tvai779q2]  a.active:hover {
    filter: brightness(1.05);
}

/* PBI #15234 — on narrow viewports the 8 module links would wrap
   to two or three rows, eating vertical space above the actual
   page. Collapse to a single horizontally-scrollable row instead.
   nowrap + overflow-x: auto keeps every link reachable via swipe;
   -webkit-overflow-scrolling: touch gives iOS the momentum feel.

   Raised from 720px to the --bp-lg stop (1024px). 720 was chosen
   for phones and happened to sit just under every iPad width, so
   the exact device this row was designed for never got it: an iPad
   in portrait (768–834) wrapped the 8 links onto two rows, and in
   landscape (1024) it was borderline. At 1024 the links usually
   still fit on one line, in which case nowrap costs nothing and no
   scrollbar appears — but when they don't fit, they swipe. */
@media (max-width: 1024px) {
    .web-module-nav[b-1tvai779q2] {
        flex-wrap: nowrap;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        /* overscroll containment stops a swipe that runs off the end
           of the tab strip from bouncing the whole page sideways. */
        overscroll-behavior-x: contain;
        scrollbar-width: none;
        /* scroll-padding keeps the active pill clear of the edge when
           the browser scrolls it into view on navigation. */
        scroll-padding-inline: 1rem;
    }

    .web-module-nav[b-1tvai779q2]::-webkit-scrollbar {
        display: none;
    }

    .web-module-nav[b-1tvai779q2]  .web-module-link {
        flex: 0 0 auto;
    }
}

/* Touch targets — the 1.85rem pill is 30px tall, well under the 44px
   floor, and these are the app's primary navigation. */
@media (pointer: coarse) {
    .web-module-nav[b-1tvai779q2]  .web-module-link {
        min-height: var(--control-h);
        padding-inline: 0.95rem;
    }
}
/* /Components/Layout/ReconnectModal.razor.rz.scp.css */
.components-reconnect-first-attempt-visible[b-lneei1k5q3],
.components-reconnect-repeated-attempt-visible[b-lneei1k5q3],
.components-reconnect-failed-visible[b-lneei1k5q3],
.components-pause-visible[b-lneei1k5q3],
.components-resume-failed-visible[b-lneei1k5q3],
.components-rejoining-animation[b-lneei1k5q3] {
    display: none;
}

#components-reconnect-modal.components-reconnect-show .components-reconnect-first-attempt-visible[b-lneei1k5q3],
#components-reconnect-modal.components-reconnect-show .components-rejoining-animation[b-lneei1k5q3],
#components-reconnect-modal.components-reconnect-paused .components-pause-visible[b-lneei1k5q3],
#components-reconnect-modal.components-reconnect-resume-failed .components-resume-failed-visible[b-lneei1k5q3],
#components-reconnect-modal.components-reconnect-retrying[b-lneei1k5q3],
#components-reconnect-modal.components-reconnect-retrying .components-reconnect-repeated-attempt-visible[b-lneei1k5q3],
#components-reconnect-modal.components-reconnect-retrying .components-rejoining-animation[b-lneei1k5q3],
#components-reconnect-modal.components-reconnect-failed[b-lneei1k5q3],
#components-reconnect-modal.components-reconnect-failed .components-reconnect-failed-visible[b-lneei1k5q3] {
    display: block;
}


#components-reconnect-modal[b-lneei1k5q3] {
    background-color: white;
    width: 20rem;
    margin: 20vh auto;
    padding: 2rem;
    border: 0;
    border-radius: 0.5rem;
    box-shadow: 0 3px 6px 2px rgba(0, 0, 0, 0.3);
    opacity: 0;
    transition: display 0.5s allow-discrete, overlay 0.5s allow-discrete;
    animation: components-reconnect-modal-fadeOutOpacity-b-lneei1k5q3 0.5s both;
    &[open]

{
    animation: components-reconnect-modal-slideUp-b-lneei1k5q3 1.5s cubic-bezier(.05, .89, .25, 1.02) 0.3s, components-reconnect-modal-fadeInOpacity-b-lneei1k5q3 0.5s ease-in-out 0.3s;
    animation-fill-mode: both;
}

}

#components-reconnect-modal[b-lneei1k5q3]::backdrop {
    background-color: rgba(0, 0, 0, 0.4);
    animation: components-reconnect-modal-fadeInOpacity-b-lneei1k5q3 0.5s ease-in-out;
    opacity: 1;
}

@keyframes components-reconnect-modal-slideUp-b-lneei1k5q3 {
    0% {
        transform: translateY(30px) scale(0.95);
    }

    100% {
        transform: translateY(0);
    }
}

@keyframes components-reconnect-modal-fadeInOpacity-b-lneei1k5q3 {
    0% {
        opacity: 0;
    }

    100% {
        opacity: 1;
    }
}

@keyframes components-reconnect-modal-fadeOutOpacity-b-lneei1k5q3 {
    0% {
        opacity: 1;
    }

    100% {
        opacity: 0;
    }
}

.components-reconnect-container[b-lneei1k5q3] {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1rem;
}

#components-reconnect-modal p[b-lneei1k5q3] {
    margin: 0;
    text-align: center;
}

#components-reconnect-modal button[b-lneei1k5q3] {
    border: 0;
    background-color: #6b9ed2;
    color: white;
    padding: 4px 24px;
    border-radius: 4px;
}

    #components-reconnect-modal button:hover[b-lneei1k5q3] {
        background-color: #3b6ea2;
    }

    #components-reconnect-modal button:active[b-lneei1k5q3] {
        background-color: #6b9ed2;
    }

.components-rejoining-animation[b-lneei1k5q3] {
    position: relative;
    width: 80px;
    height: 80px;
}

    .components-rejoining-animation div[b-lneei1k5q3] {
        position: absolute;
        border: 3px solid #0087ff;
        opacity: 1;
        border-radius: 50%;
        animation: components-rejoining-animation-b-lneei1k5q3 1.5s cubic-bezier(0, 0.2, 0.8, 1) infinite;
    }

        .components-rejoining-animation div:nth-child(2)[b-lneei1k5q3] {
            animation-delay: -0.5s;
        }

@keyframes components-rejoining-animation-b-lneei1k5q3 {
    0% {
        top: 40px;
        left: 40px;
        width: 0;
        height: 0;
        opacity: 0;
    }

    4.9% {
        top: 40px;
        left: 40px;
        width: 0;
        height: 0;
        opacity: 0;
    }

    5% {
        top: 40px;
        left: 40px;
        width: 0;
        height: 0;
        opacity: 1;
    }

    100% {
        top: 0px;
        left: 0px;
        width: 80px;
        height: 80px;
        opacity: 0;
    }
}
/* /Components/Pages/BidDiagram.razor.rz.scp.css */
/* BidDiagram (BidSketch) page scoped styles. Relies on the global
   tokens from /wwwroot/css/theme.css.

   Bug #15265 — these panel rules used to live as inline style="..."
   attributes on the page with raw 4px border-radius and the wrong
   fallback hex values for --border-muted / --surface-sunken. Moved
   here so the panels read from the theme's radius and color tokens
   directly, and so any future tweak lives in one place. */

.bidsketch-palette-shell[b-t4k7s0uaep] {
    flex: 0 0 240px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    overflow: visible;
    background: var(--surface-sunken);
}

.diagram-canvas-shell[b-t4k7s0uaep] {
    flex: 1 1 auto;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    overflow: auto;
    min-width: 0;
}

.bidsketch-placeholder[b-t4k7s0uaep] {
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--text-muted);
}

.bidsketch-placeholder--palette[b-t4k7s0uaep] {
    flex: 0 0 240px;
    background: var(--surface-sunken);
    font-size: 0.8rem;
}

.bidsketch-placeholder--canvas[b-t4k7s0uaep] {
    flex: 1 1 auto;
    font-size: 0.9rem;
}
/* /Components/Pages/BidMobile.razor.rz.scp.css */
/* Mobile field-crew page (PBI #13556) — scoped styles.
   Pulls from the global design tokens in /wwwroot/css/theme.css
   so the page inherits dark mode + brand colors instead of
   fighting them. Tap-target dimensions (44px / 48px) stay literal
   because they are accessibility minimums, not theme values. */

.mobile-page[b-fj1ldqjbzh] {
    font-family: var(--font-body);
    padding: var(--space-2);
    max-width: 100vw;
    color: var(--text);
}

.mobile-page h1[b-fj1ldqjbzh] {
    font-size: 1.2rem;
    margin: var(--space-2) 0 var(--space-1);
}

.mobile-page .subhead[b-fj1ldqjbzh] {
    color: var(--text-muted);
    font-size: 0.85rem;
    margin-bottom: var(--space-2);
}

.mobile-page .room-picker[b-fj1ldqjbzh] {
    position: sticky;
    top: 0;
    background: var(--surface);
    border-bottom: 1px solid var(--border);
    padding: var(--space-2) 0;
    z-index: 10;
}

.mobile-page select[b-fj1ldqjbzh],
.mobile-page input[b-fj1ldqjbzh] {
    width: 100%;
    padding: var(--space-3);
    font-size: 1rem;
    box-sizing: border-box;
    background: var(--surface);
    color: var(--text);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-xs);
}

.mobile-page button.tap[b-fj1ldqjbzh] {
    display: block;
    width: 100%;
    padding: var(--space-4);
    font-size: 1rem;
    margin: var(--space-1) 0;
    border: none;
    border-radius: var(--radius-xs);
    cursor: pointer;
    min-height: 48px; /* a11y minimum — keep literal */
}

.mobile-page button.tap.primary[b-fj1ldqjbzh] {
    background: var(--brand-sea);
    color: var(--text-inverse);
}

.mobile-page button.tap.ghost[b-fj1ldqjbzh] {
    background: var(--surface-sunken);
    color: var(--text);
}

.mobile-page button.tap.success[b-fj1ldqjbzh] {
    background: var(--status-success);
    color: #fff;
}

.mobile-page button.tap.warning[b-fj1ldqjbzh] {
    background: var(--status-warning);
    color: var(--status-warning-ink);
}

.mobile-page .item-card[b-fj1ldqjbzh] {
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    padding: var(--space-3);
    margin: var(--space-2) 0;
    background: var(--surface);
}

.mobile-page .item-card.installed[b-fj1ldqjbzh] {
    border-left: 4px solid var(--status-success);
}

.mobile-page .item-card.tested[b-fj1ldqjbzh] {
    border-left: 4px solid var(--status-info);
}

.mobile-page .item-card.both[b-fj1ldqjbzh] {
    /* "both" = installed AND tested → blend the two signals so
       the card carries information from both states without
       inventing a new color token. */
    border-left: 4px solid color-mix(in oklab, var(--status-success) 50%, var(--status-info));
}

.mobile-page .item-row[b-fj1ldqjbzh] {
    display: flex;
    justify-content: space-between;
    align-items: center;
}

.mobile-page .status-row[b-fj1ldqjbzh] {
    display: flex;
    gap: var(--space-2);
    margin-top: var(--space-2);
}

.mobile-page .status-row button[b-fj1ldqjbzh] {
    flex: 1;
    padding: 0.6rem;
    min-height: 44px; /* a11y minimum — keep literal */
}

.mobile-page .badge[b-fj1ldqjbzh] {
    display: inline-block;
    padding: 0.15rem 0.5rem;
    border-radius: 999px;
    font-size: 0.75rem;
}

.mobile-page .badge-installed[b-fj1ldqjbzh] {
    background: var(--status-success);
    color: #fff;
}

.mobile-page .badge-tested[b-fj1ldqjbzh] {
    background: var(--status-info);
    color: #fff;
}

/* PBI #15271 — page-scoped .toast styles removed. The page now
   publishes via ToastService and <AppToast /> in MainLayout
   renders one app-wide bubble (style at AppToast.razor.css). */

.mobile-page .add-form[b-fj1ldqjbzh] {
    background: var(--surface-sunken);
    padding: var(--space-3);
    border-radius: var(--radius-sm);
    margin: var(--space-2) 0;
}

.mobile-page .room-stats[b-fj1ldqjbzh] {
    display: flex;
    gap: var(--space-3);
    padding: 0.4rem 0;
    font-size: 0.85rem;
    color: var(--text-muted);
}

.mobile-page .room-stats strong[b-fj1ldqjbzh] {
    color: var(--text);
}

.mobile-page summary[b-fj1ldqjbzh] {
    cursor: pointer;
    padding: var(--space-2) 0;
    font-weight: 600;
}

/* Inline helpers — replace per-element `style="color:#666"` etc.
   so the page renders in dark mode and we don't leak raw hex. */
.mobile-page .mobile-error[b-fj1ldqjbzh] {
    color: var(--status-danger);
}

.mobile-page .mobile-muted[b-fj1ldqjbzh] {
    color: var(--text-muted);
}

.mobile-page .room-label[b-fj1ldqjbzh] {
    display: block;
    font-weight: 600;
    margin-bottom: var(--space-1);
}

.mobile-page .pick-room-hint[b-fj1ldqjbzh] {
    margin-top: var(--space-4);
    color: var(--text-muted);
}

.mobile-page .add-form-hint[b-fj1ldqjbzh] {
    font-size: 0.8rem;
    color: var(--text-muted);
    margin: var(--space-1) 0;
}

.mobile-page .photo-uploading[b-fj1ldqjbzh] {
    margin: var(--space-1) 0;
    color: var(--text-muted);
}

.mobile-page .photo-tally[b-fj1ldqjbzh] {
    margin-top: var(--space-3);
    font-size: 0.85rem;
}

.mobile-page .empty-room[b-fj1ldqjbzh] {
    color: var(--text-muted);
    padding: var(--space-4) 0;
}

.mobile-page .item-description[b-fj1ldqjbzh] {
    color: var(--text-muted);
    margin-left: 0.4rem;
    font-size: 0.85rem;
}

.mobile-page .item-qty[b-fj1ldqjbzh] {
    white-space: nowrap;
    font-size: 0.85rem;
    color: var(--text-muted);
}

.mobile-page .item-badges[b-fj1ldqjbzh] {
    margin-top: var(--space-1);
}
/* /Components/Pages/Home.razor.rz.scp.css */
/* Home page scoped styles. Relies on the global tokens from
   /wwwroot/css/theme.css. */

.home-hero[b-1sivlem6g5] {
    display: grid;
    grid-template-columns: minmax(0, 1.2fr) minmax(18rem, 1fr);
    gap: 1.25rem;
    align-items: center;
    overflow: hidden;
}

.home-hero__copy[b-1sivlem6g5] {
    min-width: 0;
}

.home-hero__ctas[b-1sivlem6g5] {
    display: flex;
    flex-wrap: wrap;
    gap: 0.65rem;
    margin-top: 1rem;
}

.home-hero__art[b-1sivlem6g5] {
    position: relative;
    display: grid;
    place-items: center;
    padding: 0.25rem;
    /* The shipped splash PNG is roughly 16:9 (about 1.9:1).
       Framing it via aspect-ratio keeps the hero panel a
       consistent shape while Grok / swap-in art may vary
       slightly in output dimensions. */
    aspect-ratio: 16 / 9;
    min-height: 14rem;
    max-height: 22rem;
    border-radius: var(--radius-md);
    overflow: hidden;
    /* Subtle tinted bed behind the image so a PNG with a
       transparent background still reads as a framed focal. */
    background:
        linear-gradient(180deg,
            color-mix(in oklab, var(--brand-sea-soft) 70%, var(--surface)) 0%,
            var(--surface) 100%);
    box-shadow: inset 0 0 0 1px var(--border);
}

.home-hero__art picture[b-1sivlem6g5],
.home-hero__art picture img[b-1sivlem6g5],
.home-hero__art > img[b-1sivlem6g5] {
    width: 100%;
    height: 100%;
    display: block;
    object-fit: cover;
    object-position: 50% 42%;
    /* Soft halo around the whole image so it feels lifted off
       the card; the inner glow in the artwork itself handles
       the rest. */
    filter: drop-shadow(0 18px 34px color-mix(in oklab, var(--brand-sea) 22%, transparent));
}

/* Collapse to single column on small screens — art goes
   underneath the copy so the call-to-action stays above the
   fold. */
@media (max-width: 1024px) {
    .home-hero[b-1sivlem6g5] {
        grid-template-columns: 1fr;
    }
    .home-hero__art[b-1sivlem6g5] {
        order: 2;
    }
    .home-hero__copy[b-1sivlem6g5] {
        order: 1;
    }
}
/* /Components/Pages/Portal/Dashboard.razor.rz.scp.css */
/*
 * PBI #13780 / Task #13785 — portal theme polish.
 *
 * Scoped to Dashboard.razor + reused by PortalBidDetail/CommentThread
 * via deep selectors below. ALL colors via theme tokens — no hex.
 * The portal eventually serves logged-in customers; styling matches
 * the existing app shell (same theme.css tokens) so light + dark
 * theme parity is automatic.
 */

[b-0n0xvi9dk4] .portal-header {
    display: grid;
    grid-template-columns: 1fr auto;
    align-items: start;
    gap: 1.5rem;
    margin-bottom: 1.5rem;
}

[b-0n0xvi9dk4] .portal-header__brand {
    min-width: 0;
}

[b-0n0xvi9dk4] .portal-header .app-headline {
    margin: 0.15rem 0 0.4rem;
}

[b-0n0xvi9dk4] .portal-rep-card {
    background: var(--brand-sea-soft);
    border: 1px solid var(--border);
    border-radius: 0.55rem;
    padding: 0.85rem 1rem;
    min-width: 14rem;
    color: var(--text);
}

[b-0n0xvi9dk4] .portal-rep-card__name {
    font-weight: 600;
    margin: 0.25rem 0 0.5rem;
    color: var(--brand-sea-ink);
}

[b-0n0xvi9dk4] .portal-rep-card p {
    margin: 0.15rem 0;
    font-size: 0.9rem;
}

[b-0n0xvi9dk4] .portal-link {
    color: var(--brand-sea);
    text-decoration: none;
}

[b-0n0xvi9dk4] .portal-link:hover {
    text-decoration: underline;
}

[b-0n0xvi9dk4] .portal-section {
    margin-bottom: 1.75rem;
}

[b-0n0xvi9dk4] .portal-section__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 0.75rem;
}

[b-0n0xvi9dk4] .portal-section__title {
    margin: 0;
    font-size: 1.1rem;
    color: var(--text);
}

/* PBI #15278 — `.portal-empty` un-scoped and promoted to a global
   alias of `.empty-state-inline` (see app.css). Previously this rule
   only matched inside Dashboard.razor's scoped CSS so CommentThread
   and PortalBidDetail (both also using .portal-empty) rendered bare
   un-styled text. The rule now lives in app.css for all three. */

/* ── Bid card grid ─────────────────────────────────────── */

[b-0n0xvi9dk4] .portal-bid-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 22rem), 1fr));
    gap: 0.85rem;
}

[b-0n0xvi9dk4] .portal-bid-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 0.55rem;
    transition: box-shadow 0.15s ease, transform 0.15s ease;
}

[b-0n0xvi9dk4] .portal-bid-card:hover {
    box-shadow: var(--shadow-md);
    transform: translateY(-1px);
}

[b-0n0xvi9dk4] .portal-bid-card__link {
    display: block;
    padding: 0.95rem 1rem;
    color: var(--text);
    text-decoration: none;
}

[b-0n0xvi9dk4] .portal-bid-card__heading {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    margin-bottom: 0.35rem;
}

[b-0n0xvi9dk4] .portal-bid-card__title {
    margin: 0;
    font-size: 1rem;
    font-weight: 600;
}

[b-0n0xvi9dk4] .portal-bid-card__meta {
    margin: 0 0 0.5rem;
    color: var(--text-muted);
    font-size: 0.85rem;
}

[b-0n0xvi9dk4] .portal-bid-card__cta {
    margin: 0;
    color: var(--brand-sea);
    font-size: 0.9rem;
    font-weight: 600;
}

/* ── Rep list ──────────────────────────────────────────── */

[b-0n0xvi9dk4] .portal-rep-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 16rem), 1fr));
    gap: 0.6rem;
}

[b-0n0xvi9dk4] .portal-rep-list__item {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 0.45rem;
    padding: 0.75rem 0.9rem;
}

[b-0n0xvi9dk4] .portal-rep-list__name {
    margin: 0 0 0.2rem;
    font-weight: 600;
    color: var(--text);
}

[b-0n0xvi9dk4] .portal-rep-list__contact {
    margin: 0;
    font-size: 0.85rem;
    color: var(--text-muted);
}

/* ── Bid detail: rooms + line items ─────────────────────── */

[b-0n0xvi9dk4] .portal-room-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 0.55rem;
    margin-bottom: 0.85rem;
    overflow: hidden;
}

[b-0n0xvi9dk4] .portal-room-card__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0.65rem 1rem;
    background: var(--surface-sunken);
    border-bottom: 1px solid var(--border);
}

[b-0n0xvi9dk4] .portal-room-card__title {
    margin: 0;
    font-size: 0.95rem;
    color: var(--text);
}

[b-0n0xvi9dk4] .portal-room-card__total {
    font-weight: 600;
    color: var(--text);
}

[b-0n0xvi9dk4] .portal-line-items {
    list-style: none;
    margin: 0;
    padding: 0;
}

[b-0n0xvi9dk4] .portal-line-item {
    display: flex;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 0.55rem 1rem;
    border-bottom: 1px solid var(--border);
}

[b-0n0xvi9dk4] .portal-line-item:last-child {
    border-bottom: none;
}

[b-0n0xvi9dk4] .portal-line-item__main {
    flex: 1 1 auto;
}

[b-0n0xvi9dk4] .portal-line-item__name {
    margin: 0;
    color: var(--text);
}

[b-0n0xvi9dk4] .portal-line-item__meta {
    margin: 0.15rem 0 0;
    font-size: 0.8rem;
    color: var(--text-muted);
}

[b-0n0xvi9dk4] .portal-line-item__price {
    margin: 0;
    flex: 0 0 auto;
    align-self: center;
    color: var(--text);
    font-variant-numeric: tabular-nums;
}

/* ── Comment thread ─────────────────────────────────────── */

[b-0n0xvi9dk4] .portal-comments {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 0.55rem;
    padding: 1rem;
}

[b-0n0xvi9dk4] .portal-comments__compose {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    margin-bottom: 1rem;
    padding-bottom: 1rem;
    border-bottom: 1px solid var(--border);
}

[b-0n0xvi9dk4] .portal-comments__label {
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--text);
}

[b-0n0xvi9dk4] .portal-comments__name,
[b-0n0xvi9dk4] .portal-comments__body {
    width: 100%;
    padding: 0.5rem 0.65rem;
    border: 1px solid var(--border);
    border-radius: 0.4rem;
    background: var(--surface);
    color: var(--text);
    font: inherit;
}

[b-0n0xvi9dk4] .portal-comments__body {
    min-height: 5rem;
    resize: vertical;
}

[b-0n0xvi9dk4] .portal-comments__error {
    margin: 0;
    padding: 0.4rem 0.6rem;
    color: var(--status-danger-ink);
    background: var(--status-danger-soft);
    border-radius: 0.35rem;
    font-size: 0.85rem;
}

[b-0n0xvi9dk4] .portal-comments__actions {
    display: flex;
    justify-content: flex-end;
}

[b-0n0xvi9dk4] .portal-comments__list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.55rem;
}

[b-0n0xvi9dk4] .portal-comment {
    background: var(--surface-sunken);
    border-left: 3px solid var(--brand-sea);
    border-radius: 0.4rem;
    padding: 0.65rem 0.85rem;
}

[b-0n0xvi9dk4] .portal-comment--rep {
    border-left-color: var(--status-success);
    background: var(--status-success-soft);
}

[b-0n0xvi9dk4] .portal-comment__head {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.25rem;
}

[b-0n0xvi9dk4] .portal-comment__author {
    font-weight: 600;
    color: var(--text);
}

[b-0n0xvi9dk4] .portal-comment__when {
    margin-left: auto;
    color: var(--text-muted);
    font-size: 0.8rem;
}

[b-0n0xvi9dk4] .portal-comment__body {
    margin: 0;
    color: var(--text);
    white-space: pre-wrap;
}

/* ── Responsive carve ──────────────────────────────────────
   The portal is the one surface in this app that is opened on a
   phone more often than anything else — a customer taps a link in
   an email to look at a bid. Phone is the design target here, not
   an afterthought, so this carve goes further than the internal
   pages do.

   Stops are the --bp-* scale from theme.css. The 768 stop was 720
   before this pass; 720 sat just under every iPad width, so an iPad
   in portrait held the two-column header and squeezed the bid list
   to a single narrow column of cards. */

@media (max-width: 768px) {
    [b-0n0xvi9dk4] .portal-header {
        grid-template-columns: 1fr;
        gap: 1rem;
    }

    [b-0n0xvi9dk4] .portal-rep-card {
        min-width: 0;
    }

    [b-0n0xvi9dk4] .portal-section {
        margin-bottom: 1.25rem;
    }
}

@media (max-width: 640px) {
    /* Title and action stop sharing a line — the action is usually a
       link whose label is longer than the space left beside a
       section title. */
    [b-0n0xvi9dk4] .portal-section__head {
        flex-direction: column;
        align-items: flex-start;
        gap: 0.35rem;
    }

    /* Name-left / price-right holds until the name wraps to three
       lines and drags the price down beside its own last word.
       Stack, and let the price sit under the name as its own line. */
    [b-0n0xvi9dk4] .portal-line-item {
        flex-direction: column;
        gap: 0.2rem;
    }

    [b-0n0xvi9dk4] .portal-line-item__price {
        align-self: flex-start;
        font-weight: 600;
    }

    [b-0n0xvi9dk4] .portal-room-card__head {
        flex-wrap: wrap;
        gap: 0.25rem 0.75rem;
    }

    /* A right-aligned Post button on a phone is a 6rem target in the
       far corner. Full width instead. */
    [b-0n0xvi9dk4] .portal-comments__actions {
        justify-content: flex-start;
    }

    [b-0n0xvi9dk4] .portal-comments__actions > * {
        width: 100%;
        justify-content: center;
    }

    [b-0n0xvi9dk4] .portal-comments {
        padding: 0.85rem 0.75rem;
    }

    [b-0n0xvi9dk4] .portal-comment__head {
        flex-wrap: wrap;
    }

    [b-0n0xvi9dk4] .portal-comment__when {
        margin-left: 0;
        flex-basis: 100%;
    }
}

/* Touch targets — the portal's tap targets are links inside cards,
   which have no min-height of their own at all. */
@media (pointer: coarse) {
    [b-0n0xvi9dk4] .portal-bid-card__link {
        padding: 1.05rem 1rem;
    }

    [b-0n0xvi9dk4] .portal-link {
        display: inline-block;
        padding-block: 0.35rem;
    }

    [b-0n0xvi9dk4] .portal-comments__name,
    [b-0n0xvi9dk4] .portal-comments__body {
        min-height: var(--control-h);
        /* iOS zooms the page on focus below 16px; see theme.css. */
        font-size: 16px;
    }

    /* Hover lift latches after a tap and leaves one card floating. */
    [b-0n0xvi9dk4] .portal-bid-card:hover {
        transform: none;
    }
}
/* /Components/Pages/Portal/Login.razor.rz.scp.css */
/*
 * PBI #13786 / Task #13787 — portal auth pages styles.
 * Scoped via Login.razor's component CSS but applied to siblings
 * (PasswordRequest.razor) via ::deep selectors. Theme tokens only.
 */

[b-5r1tlarazi] .portal-auth-shell {
    display: flex;
    align-items: center;
    justify-content: center;
    /* dvh, not vh: on iOS Safari 100vh is the height with the URL bar
       hidden, so a vh-based min-height pushes the card below the fold
       on first paint and the page opens scrolled. */
    min-height: calc(100dvh - 6rem);
    padding: 2rem 1rem calc(2rem + var(--safe-b));
}

[b-5r1tlarazi] .portal-auth-card {
    max-width: 30rem;
    width: 100%;
}

[b-5r1tlarazi] .portal-auth-form {
    display: flex;
    flex-direction: column;
    gap: 0.45rem;
    margin-top: 1rem;
}

[b-5r1tlarazi] .portal-auth-label {
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--text);
    margin-top: 0.4rem;
}

[b-5r1tlarazi] .portal-auth-input {
    padding: 0.55rem 0.75rem;
    border: 1px solid var(--border);
    border-radius: 0.4rem;
    background: var(--surface);
    color: var(--text);
    font: inherit;
}

[b-5r1tlarazi] .portal-auth-input:focus {
    outline: 2px solid var(--ring);
    outline-offset: 1px;
    border-color: var(--brand-sea);
}

[b-5r1tlarazi] .portal-auth-checkbox {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin: 0.35rem 0 0.6rem;
    font-size: 0.9rem;
    color: var(--text);
}

[b-5r1tlarazi] .portal-auth-banner {
    margin-top: 0.85rem;
    padding: 0.55rem 0.75rem;
    border-radius: 0.4rem;
    font-size: 0.9rem;
}

[b-5r1tlarazi] .portal-auth-banner--ok {
    background: var(--status-success-soft);
    color: var(--status-success-ink);
}

[b-5r1tlarazi] .portal-auth-banner--err {
    background: var(--status-danger-soft);
    color: var(--status-danger-ink);
}

[b-5r1tlarazi] .portal-auth-foot {
    margin: 1rem 0 0;
    text-align: center;
    font-size: 0.9rem;
}

/* ── Responsive carve ──────────────────────────────────────
   Sign-in is where a customer's session starts and it is nearly
   always started on a phone. Stops are the --bp-* scale in
   theme.css. */

@media (max-width: 640px) {
    [b-5r1tlarazi] .portal-auth-shell {
        /* Centering a card that is nearly as tall as the viewport
           just clips it symmetrically once the keyboard opens.
           Top-align and let the field the user tapped stay visible. */
        align-items: flex-start;
        padding: 1rem 0.85rem calc(1.5rem + var(--safe-b));
        min-height: 0;
    }

    [b-5r1tlarazi] .portal-auth-card {
        max-width: none;
    }

    [b-5r1tlarazi] .portal-auth-form .app-cta {
        width: 100%;
    }
}

@media (pointer: coarse) {
    [b-5r1tlarazi] .portal-auth-input {
        min-height: var(--control-h);
        /* 16px is the iOS focus-zoom threshold, not a design size —
           see the note in theme.css. */
        font-size: 16px;
    }

    /* A native checkbox is ~13px; the label is the real target, so
       give the whole row a tappable height. */
    [b-5r1tlarazi] .portal-auth-checkbox {
        min-height: var(--control-h);
    }
}
/* /Components/Shared/AppToast.razor.rz.scp.css */
/* PBI #15271 — app-wide toast. Style ported from BidMobile's
   page-scoped .toast (the only auto-dismissing surface in the app
   before this work item) so the visual feel is preserved during
   the rollout. Tokens drive every color; no hard-coded hex. */

.app-toast[b-j9zlxaycx6] {
    position: fixed;
    bottom: var(--space-4);
    left: 50%;
    transform: translateX(-50%);
    background: var(--text);
    color: var(--text-inverse);
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius-xs);
    opacity: 0.95;
    z-index: var(--z-toast);
    box-shadow: var(--shadow-sm);
    max-width: min(90vw, 28rem);
    text-align: center;
}

.app-toast.error[b-j9zlxaycx6] {
    background: var(--status-danger);
    color: #fff;
}
