/* Web-only styles for ToolboxApp.App.Endpoint.
   Loaded AFTER _content/ToolboxApp.Shared.UI/css/shared.css (see App.razor), so any
   rule here beats shared.css at equal specificity — including shared.css's @media
   overrides, which carry no extra weight. Never copy a shared.css rule into this file
   "for reference": a duplicated base rule silently disables its responsive variants on
   web while still looking correct in shared.css, and it only breaks on the web app
   (MAUI loads shared.css alone). Put shared styles in shared.css and web-only styles
   here. A rule that intentionally differs from shared.css is fine, but say why.

   Third link in App.razor, and last, is MudBlazor.min.css — so MudBlazor's own rules beat
   BOTH files at equal specificity. Any property MudBlazor also declares on the same class
   (display, padding, margin, colour on .mud-* components) needs !important or a more
   specific selector, and since the package floats at `9.*`, prefer !important. A rule that
   looks correct here and still does nothing is usually this, not shared.css. */

/* === Self-hosted Roboto (variable font, latin subset) === */
@font-face {
    font-family: 'Roboto';
    font-style: normal;
    font-weight: 300 500;
    font-stretch: 100%;
    font-display: swap;
    src: url('/fonts/roboto-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
        U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191,
        U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* === Base Styles === */
html, body {
    height: 100%;
    margin: 0;
}

/* === Layout === */

.appbar-logo {
    height: 48px;
    margin-left: -8px;
    vertical-align: middle;
}

.appbar-logo-link {
    display: flex;
    align-items: center;
}

.breadcrumb-bar {
    background-color: var(--mud-palette-tertiary);
    padding: 6px 12px !important;
    min-height: 0 !important;
    font-size: 14px;
}

.breadcrumb-bar * {
    color: var(--breadcrumb-color) !important;
}

/* An active manufacturer label (brand-accented on MudLayout, --brand-accent from the Brand
   record) recolors the breadcrumb bar to the brand's accent, with white text to match. */
.brand-accented .breadcrumb-bar {
    background-color: var(--brand-accent);
}

.brand-accented .breadcrumb-bar * {
    color: #fff !important;
}

.layout-content {
    padding: 0;
    width: 100%;
    overflow-y: auto;
    flex: 1;
    min-height: 0;
}

.tool-detail-row .detail-value--multiline {
    white-space: pre-line;
}

/* About text with a bulleted list (AboutTextFormatter). */
.tool-detail-row .about-paragraph {
    margin: 0 0 4px;
}

.tool-detail-row .about-list {
    margin: 0;
    padding-left: 20px;
    list-style: disc;
}

.tool-detail-row .about-list ul {
    margin: 2px 0 0;
    padding-left: 20px;
    list-style: circle;
}

.tool-detail-row .about-list li {
    margin-bottom: 4px;
}

/* === Select / Autocomplete highlight === */
.mud-list-item-gutters.mud-list-item-clickable:hover {
    background-color: var(--mud-palette-action-default-hover) !important;
}

.mud-list-item-gutters.mud-selected-item {
    background-color: var(--mud-palette-divider) !important;
}

.mud-list-item-gutters.mud-selected-item .mud-list-item-text,
.mud-list-item-gutters.mud-selected-item .mud-list-item-text * {
    color: var(--mud-palette-text-primary) !important;
}

/* === Tooltips === */
.mud-tooltip {
    font-size: 14px !important;
}

/* === Hide number input spinners === */
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

input[type="number"] {
    -moz-appearance: textfield;
    appearance: textfield;
}

.oa-station-cta-actions {
    display: flex;
    gap: 0.5rem;
}

.mud-radio-group {
    gap: 16px;
}

/* === Sidebar Nav === */

/* Brand on top and the footer (weather station down to the copyright) stay put; only the
   category list between them scrolls. Scrolling the whole nav instead pushed the footer
   off-screen as soon as a long category was expanded. */
.sidebar-nav {
    padding: 0;
    height: 100%;
    overflow: hidden;
    display: flex;
    flex-direction: column;
}

/* min-height: 0 is what lets a flex child shrink below its content and actually scroll. */
.sidebar-nav > .mud-navmenu {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
}

.sidebar-nav > .sidebar-brand,
.sidebar-nav > .sidebar-footer {
    flex: 0 0 auto;
}

/* Very short windows: a pinned footer would leave the list only a sliver, so fall back to
   scrolling the whole nav. */
@media (max-height: 560px) {
    .sidebar-nav {
        overflow-y: auto;
    }

    .sidebar-nav > .mud-navmenu {
        flex: 0 0 auto;
        overflow-y: visible;
    }
}

.sidebar-brand {
    display: flex;
    align-items: center;
    padding: 6px 16px;
    font-size: 1rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.18em;
    color: #fff;
    background: var(--mud-palette-secondary);
}

.nav-external-icon {
    opacity: 0.5;
    font-size: 14px !important;
    margin-bottom: -2px;
}

.sidebar-brand-link {
    display: flex;
    align-items: center;
    gap: 12px;
    color: inherit;
    text-decoration: none;
}

/* Parent group headers */
.nav-group-header {
    font-weight: 600 !important;
    font-size: 0.8rem !important;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    background: var(--mud-palette-divider) !important;
    border-top: 1px solid rgba(var(--mud-palette-info-rgb), 0.15);
}

.mud-nav-group:last-child {
    border-bottom: 1px solid rgba(var(--mud-palette-info-rgb), 0.15);
}

/* Heavier border on the pinned Favorites group to set it apart from the category groups */
.nav-favorites-group {
    border-bottom: 4px solid rgba(var(--mud-palette-info-rgb), 0.3);
}

.nav-group-active,
.nav-group-active .mud-nav-link-icon {
    color: var(--mud-palette-info) !important;
}

.mud-drawer .mud-nav-group .mud-collapse .mud-nav-link {
    border-bottom: 1px solid var(--mud-palette-divider);
}

.mud-drawer .mud-nav-link:hover,
.mud-drawer .mud-nav-link.active {
    background: rgba(var(--mud-palette-info-rgb), 0.15) !important;
}

/* App store badges — fixed size, softened, brighten to full opacity on hover */
.app-store-badge { width: 130px; height: 42px; display: block; opacity: 0.85; transition: opacity 0.15s ease; }
.app-store-badge:hover { opacity: 1; }

/* Right-aligned in the About card on most screens, left-aligned on phones (<600px) */
.app-store-badges { justify-content: flex-end; }
@media (max-width: 600px) { .app-store-badges { justify-content: flex-start; } }

/* === Focus Styles === */
:focus-visible {
    outline: 2px solid var(--mud-palette-primary);
    outline-offset: 2px;
}

/* Wide-desktop only: the sidebar is roomy enough to pair up result cards; on MAUI
   shared.css keeps them full width. */
@media (min-width: 1600px) {
    .psychro-sidebar .psychro-results > .mud-paper {
        width: calc(50% - 4px);
    }
}

@media (min-width: 2560px) {
    .psychro-sidebar .psychro-results > .mud-paper {
        width: calc(33.33% - 6px);
    }
}

/* === Responsive === */
/* Phones: drop the breadcrumb bar. Three crumbs plus separators wrap to two lines at this
   width and cost more vertical space than they save in navigation — the drawer and the
   browser Back button already cover going up a level. This also hides the home page's
   `&nbsp;` spacer strip, which shares the class (MainLayout renders it in place of the
   crumbs), so the band disappears on every route instead of leaving one empty coloured bar.
   The BreadcrumbList JSON-LD is emitted independently in each page's head via
   SeoSchemas.BuildBreadcrumbSchema, so the rich result is unaffected.

   !important because MudBlazor.min.css is linked LAST in App.razor and sets
   `display: flex` on `.mud-breadcrumbs`, the same specificity as `.breadcrumb-bar`, so it
   wins on order. Without it only the home page's plain <div> was hidden — it carries no
   .mud-breadcrumbs class, so nothing overrode it — while every calculator page kept its
   crumbs. Out-specifying is not the fix here: MudBlazor is referenced as `9.*`, so its
   selectors are not ours to depend on. This is the same reason the base rule above forces
   padding and min-height. */
@media (max-width: 600px) {
    .breadcrumb-bar {
        display: none !important;
    }
}

@media (max-width: 1280px) {
    /* Centered over the toolbar, so it must never grow into the drawer toggle (left)
       or the feedback + theme buttons (right). Centering makes the reservation symmetric:
       248px is two 48px icon buttons plus the toolbar gutter, on each side; the logo
       scales down inside whatever is left. On phones the rule below overrides this and
       centers the logo over the free space between the button groups instead. */
    .appbar-logo-link {
        position: absolute;
        left: 50%;
        transform: translateX(-50%);
        max-width: calc(100% - 248px);
    }
    /* The SVGs are natively much larger than they render (the CaptiveAire mark is
       864x119), so width/height must never both go auto — that drops the element's
       width/height attributes and the logo springs to full natural size. Pin the box
       to the brand's own ratio instead (--logo-ar, set inline from the Brand record)
       so it scales down uniformly and stays capped at its normal 48px height. */
    .appbar-logo {
        margin-left: 0;
        height: auto;
        max-height: 48px;
        max-width: 100%;
        aspect-ratio: var(--logo-ar);
    }
}

/* Phones: the symmetric 248px reservation above would shrink the logo badly, because only
   the right side carries two buttons. Center it over the actual free space instead (the
   translateX(-50%) above still applies, so `left` is the logo's center). Below 600px the
   MudBlazor toolbar gutter is 16px and an icon button is 48px: the left group ends at
   16 - 12 (Edge.Start) + 48 = 52px, the right group starts 48 + 48 + 16 = 112px from the
   right edge. Center = (52 + 100% - 112) / 2 = 50% - 30px; width = 100% - 164px, minus
   4px slack each side. Must come after the 1280px block (same specificity, wins on order). */
@media (max-width: 599.98px) {
    .appbar-logo-link {
        left: calc(50% - 30px);
        max-width: calc(100% - 172px);
    }
}

/* Blazor circuit reconnect UI — rolling update resilience */
.blazor-reconnect-hide {
    display: none;
}

#components-reconnect-modal.components-reconnect-show,
#components-reconnect-modal.components-reconnect-failed,
#components-reconnect-modal.components-reconnect-rejected {
    display: flex;
    align-items: center;
    justify-content: center;
    position: fixed;
    inset: 0;
    z-index: 10000;
}

#components-reconnect-modal .blazor-reconnect-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.3);
    backdrop-filter: blur(2px);
}

#components-reconnect-modal .blazor-reconnect-dialog {
    position: relative;
    background: var(--mud-palette-surface, #fff);
    color: var(--mud-palette-text-primary, #333);
    border-radius: 8px;
    padding: 1rem 1.5rem;
    text-align: center;
    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.15);
    z-index: 1;
}

#components-reconnect-modal .blazor-reconnect-message {
    margin: 0;
    font-size: 0.95rem;
    font-weight: 500;
}

#components-reconnect-modal .blazor-reconnect-spinner + .blazor-reconnect-message,
#components-reconnect-modal .blazor-reconnect-message + .blazor-reconnect-spinner {
    margin-top: 0.75rem;
}

#components-reconnect-modal .blazor-reconnect-spinner {
    width: 28px;
    height: 28px;
    margin: 0 auto;
    border: 3px solid var(--mud-palette-lines-default, #ddd);
    border-top-color: var(--mud-palette-primary, #1976d2);
    border-radius: 50%;
    animation: blazor-reconnect-spin 0.8s linear infinite;
}

@keyframes blazor-reconnect-spin {
    to { transform: rotate(360deg); }
}

/* State-scoped visibility: elements are hidden by default and revealed only
   when the modal carries the matching framework state class. */
#components-reconnect-modal .blazor-reconnect-show-only,
#components-reconnect-modal .blazor-reconnect-failed-only,
#components-reconnect-modal .blazor-reconnect-rejected-only {
    display: none;
}

#components-reconnect-modal.components-reconnect-show .blazor-reconnect-show-only,
#components-reconnect-modal.components-reconnect-failed .blazor-reconnect-failed-only,
#components-reconnect-modal.components-reconnect-rejected .blazor-reconnect-rejected-only {
    display: revert;
}

#components-reconnect-modal.components-reconnect-show .blazor-reconnect-spinner.blazor-reconnect-show-only {
    display: block;
}

/* Circuit-died UI. Hidden until blazor.web.js sets an inline display:block on the root, which
   is why the dialog centers itself with fixed positioning rather than relying on the root being
   a flex container. Matches the reconnect dialog above. MudBlazor styles this id as a red
   bottom bar (background, padding, shadow, width), so those are reset here. */
#blazor-error-ui {
    display: none;
    position: fixed;
    inset: 0;
    width: auto;
    height: auto;
    z-index: 10000;
    padding: 0;
    background: none;
    box-shadow: none;
    color: inherit;
}

#blazor-error-ui .blazor-error-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.3);
    backdrop-filter: blur(2px);
}

#blazor-error-ui .blazor-error-dialog {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: max-content;
    max-width: calc(100% - 32px);
    box-sizing: border-box;
    background: var(--mud-palette-surface, #fff);
    color: var(--mud-palette-text-primary, #333);
    border-radius: 8px;
    padding: 1rem 1.5rem;
    text-align: center;
    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.15);
}

#blazor-error-ui .blazor-error-message {
    margin: 0;
    font-size: 0.95rem;
    font-weight: 500;
}

#blazor-error-ui .blazor-error-reload {
    margin-top: 0.75rem;
    padding: 6px 16px;
    border: none;
    border-radius: 4px;
    background: var(--mud-palette-primary, #1976d2);
    color: var(--mud-palette-primary-text, #fff);
    font: inherit;
    font-weight: 500;
    cursor: pointer;
}


/* === Print: Static Pressure Calculator — the run as a report sheet ===
   Web-only (the MAUI WebView cannot print), so it lives here rather than shared.css. The
   component renders a .sp-report block that .print-only (shared.css) hides on screen; these
   rules hide everything else, release the app-shell scroll container the way the
   psychrometric chart's print rules do, and lay the report out from the top of the sheet.
   Scoped with :has(.sp-report) so no other page is touched. */
@media print {
    /* Remove (not merely hide) everything that is not the report or on the path to it:
       visibility:hidden would keep the on-screen layout's height and print blank sheets
       after the report. Ancestors stay, as they must for the report to render. */
    body:has(.sp-report) *:not(:has(.sp-report)):not(.sp-report):not(.sp-report *) {
        display: none !important;
    }

    /* Kill the scroll container and the app-bar padding, or the report prints clipped to
       one screen and pushed down the page. */
    html:has(.sp-report),
    body:has(.sp-report),
    body:has(.sp-report) .mud-layout,
    body:has(.sp-report) .mud-main-content,
    body:has(.sp-report) main,
    body:has(.sp-report) .layout-content {
        overflow: visible !important;
        height: auto !important;
        min-height: 0 !important;
        max-height: none !important;
        padding-top: 0 !important;
        margin-top: 0 !important;
        background: #fff !important;
    }

    body:has(.sp-report) .sp-report {
        position: absolute;
        left: 0;
        top: 0;
        width: 100%;
        margin: 0;
        padding: 0;
        background: #fff;
        /* Light palette regardless of the on-screen theme. */
        color: rgba(0, 0, 0, 0.87) !important;
        font-size: 9.5pt;
        line-height: 1.35;
        print-color-adjust: exact;
        -webkit-print-color-adjust: exact;
    }

    .sp-report-header {
        display: flex;
        justify-content: space-between;
        align-items: flex-end;
        gap: 16px;
        padding-bottom: 6px;
        margin-bottom: 10px;
        border-bottom: 2px solid #222;
    }

    .sp-report-title {
        font-size: 15pt;
        font-weight: 600;
        line-height: 1.2;
    }

    .sp-report-name {
        font-size: 11pt;
        font-weight: 500;
        margin-top: 2px;
    }

    .sp-report-date {
        font-size: 9pt;
        color: rgba(0, 0, 0, 0.6);
        white-space: nowrap;
    }

    .sp-report-table {
        width: 100%;
        border-collapse: collapse;
        font-size: 8.5pt;
    }

    .sp-report-table thead {
        display: table-header-group;   /* repeat the header when a long run breaks pages */
    }

    .sp-report-table tr {
        break-inside: avoid;
    }

    .sp-report-table th,
    .sp-report-table td {
        padding: 3px 5px;
        text-align: left;
        vertical-align: top;
        border-bottom: 1px solid #ccc;
    }

    .sp-report-table th {
        font-size: 7.5pt;
        font-weight: 600;
        text-transform: uppercase;
        letter-spacing: 0.3px;
        color: rgba(0, 0, 0, 0.7);
        border-bottom: 1px solid #222;
        vertical-align: bottom;
    }

    /* The two text columns get the room; a numeric header may wrap, a numeric value never. */
    .sp-report-table th:nth-child(2),
    .sp-report-table td:nth-child(2) {
        width: 12%;
    }

    .sp-report-table th:nth-child(6),
    .sp-report-table td:nth-child(6) {
        width: 29%;
    }

    .sp-report-table .num {
        text-align: right;
    }

    .sp-report-table td.num {
        white-space: nowrap;
    }

    /* Inputs (length, airflow, velocity) centred; the losses stay right-aligned so their
       decimals line up down to the totals. */
    .sp-report-table .mid {
        text-align: center;
    }

    .sp-report-table td.mid {
        white-space: nowrap;
    }

    .sp-report-totals {
        width: 300px;
        margin: 10px 0 0 auto;
    }

    .sp-report-totals > div {
        display: flex;
        justify-content: space-between;
        gap: 16px;
        padding: 2px 0;
    }

    .sp-report-totals > div > span:last-child {
        white-space: nowrap;
    }

    .sp-report-totals .sp-report-total {
        margin-top: 4px;
        padding-top: 5px;
        border-top: 1px solid #222;
        font-size: 11pt;
        font-weight: 700;
    }

    /* Plain lines, not bullets: the compression notes lead with the asterisk the Duct
       cell points at, and a bullet in front of that would compete with it. */
    .sp-report-notes {
        margin: 12px 0 0;
        padding-left: 0;
        list-style: none;
        font-size: 8.5pt;
    }

    .sp-report-notes li {
        margin-bottom: 2px;
    }

    .sp-report-basis {
        margin-top: 12px;
        font-size: 8pt;
        color: rgba(0, 0, 0, 0.6);
    }

    .sp-report-link {
        margin-top: 6px;
        font-size: 8pt;
        color: rgba(0, 0, 0, 0.6);
        word-break: break-all;
    }
}

/* Feedback drawer title bar (web only): page-header color, and exactly the app bar's height —
   MudToolbar is 56px below 600px and 64px from 600px up. MudDrawerHeader's own 64px min-height
   plus 12px padding made it 72px. */
.feedback-drawer-header {
    background: var(--mud-palette-secondary);
    color: #fff;
    height: 64px;
    min-height: 64px;
    padding-top: 0;
    padding-bottom: 0;
}

@media (max-width: 599.98px) {
    .feedback-drawer-header {
        height: 56px;
        min-height: 56px;
    }
}
