/* Truss web UI. MudBlazor supplies the components; this file covers the shell (navigation, login) and a
   few layout rules MudBlazor leaves to the app. Colors match Theme/TrussTheme.cs. */

:root {
    --truss-navy: #0a1931;
    --truss-blue: #0085FF;
    --truss-text: #292d32;
    --truss-muted: #4a5568;
    --truss-border: #dcdfe4;
    --truss-bg: #f3f5f7;
}

html, body {
    font-family: Poppins, "Segoe UI", Helvetica, Arial, sans-serif;
    background: var(--truss-bg);
    color: var(--truss-text);
    margin: 0;
}

/* ---- Application shell ------------------------------------------------- */

.truss-appbar-logo {
    height: 28px;
    margin-left: 8px;
}

.truss-drawer {
    background: var(--truss-navy);
}

.truss-nav {
    display: flex;
    flex-direction: column;
    height: 100%;
    color: #d5dbe6;
}

.truss-nav-logo {
    display: flex;
    justify-content: center;
    padding: 24px 24px 16px;
}

.truss-nav-logo img {
    width: 120px;
    display: block;
}

.truss-nav-menu {
    flex: 1;
}

.truss-nav-menu .mud-nav-link {
    color: #d5dbe6;
    padding-left: 24px;
}

.truss-nav-menu .mud-nav-link .mud-icon-root {
    color: #d5dbe6;
}

.truss-nav-menu .mud-nav-link.active {
    color: #ffffff;
    background: rgba(0, 133, 255, 0.25);
    border-right: 3px solid var(--truss-blue);
}

.truss-nav-menu .mud-nav-link.active .mud-icon-root {
    color: #ffffff;
}

/* A group's own header is also a .mud-nav-link; its pages sit one step in. */
.truss-nav-menu .truss-nav-group > .mud-nav-link {
    color: #d5dbe6;
}

.truss-nav-menu .truss-nav-group .mud-nav-link .mud-nav-link-expand-icon {
    color: #d5dbe6;
}

.truss-nav-menu .truss-nav-group .mud-collapse-container .mud-nav-link {
    padding-left: 40px;
}

.truss-template-toggles {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 16px;
    margin-bottom: 8px;
}

.truss-template-toggles .mud-toggle-group {
    flex: 1;
    min-width: 260px;
}

.truss-nav-footer {
    padding: 16px 24px 24px;
    border-top: 1px solid rgba(255, 255, 255, 0.12);
}

.truss-nav-user {
    font-size: 12px;
    color: #959aa7;
    margin-bottom: 8px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.truss-nav-logout {
    display: inline-flex;
    align-items: center;
    background: none;
    border: none;
    color: #d5dbe6;
    font: inherit;
    font-size: 14px;
    cursor: pointer;
    padding: 6px 0;
}

.truss-nav-logout:hover {
    color: #ffffff;
}

/* Demo mode, above the user: a red light that blinks like a recording light, still for a reader who asked for
   reduced motion (docs/decisions/26-09-27-20-25-31-web-ui-demo-mode.md). */
.truss-demo-indicator {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    margin-bottom: 12px;
    font-size: 12px;
    color: #ffffff;
}

.truss-demo-light {
    flex: none;
    width: 10px;
    height: 10px;
    margin-top: 3px;
    border-radius: 50%;
    background: #ff3b30;
    box-shadow: 0 0 6px #ff3b30;
    animation: truss-demo-blink 1.2s ease-in-out infinite;
}

.truss-demo-label {
    display: block;
    font-weight: 600;
}

.truss-demo-times {
    display: block;
    color: #d5dbe6;
}

@keyframes truss-demo-blink {
    0%, 100% {
        opacity: 1;
    }

    50% {
        opacity: 0.2;
    }
}

@media (prefers-reduced-motion: reduce) {
    .truss-demo-light {
        animation: none;
    }
}

/* As wide as the window less the drawer: MudMainContent is offset by the drawer's width, and nothing here
   narrows it further. */
.truss-page {
    padding: 24px;
}

/* The app bar exists for the drawer toggle on narrow screens only. On wide screens the drawer is always
   open, so the bar and the space MudBlazor reserves for it both go. */
@media (min-width: 960px) {
    .truss-appbar {
        display: none;
    }

    .truss-main {
        padding-top: 0 !important;
    }
}

@media (max-width: 959.98px) {
    .truss-page {
        padding: 16px;
    }
}

/* ---- Login ----------------------------------------------------------- */

.truss-login-shell {
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 16px;
    box-sizing: border-box;
}

.truss-login-card {
    background: #ffffff;
    border: 1px solid var(--truss-border);
    border-radius: 8px;
    padding: 40px 32px;
    width: 100%;
    max-width: 420px;
    box-sizing: border-box;
}

.truss-login-logo {
    width: 140px;
    display: block;
    margin: 0 auto 24px;
}

.truss-login-title {
    font-size: 22px;
    font-weight: 500;
    margin: 0 0 8px;
    text-align: center;
}

.truss-login-hint {
    color: var(--truss-muted);
    font-size: 14px;
    text-align: center;
    margin: 0 0 24px;
}

.truss-login-error {
    background: #fdecea;
    color: #8a1c14;
    border: 1px solid #f5c2bd;
    border-radius: 6px;
    padding: 10px 12px;
    font-size: 14px;
    margin-bottom: 16px;
}

.truss-login-form {
    display: flex;
    flex-direction: column;
}

.truss-login-label {
    font-size: 13px;
    color: var(--truss-muted);
    margin-bottom: 6px;
}

.truss-login-input {
    font: inherit;
    font-size: 16px;
    padding: 10px 12px;
    border: 1px solid var(--truss-border);
    border-radius: 6px;
    margin-bottom: 16px;
}

.truss-login-input:focus {
    outline: 2px solid var(--truss-blue);
    outline-offset: 0;
    border-color: var(--truss-blue);
}

.truss-login-code {
    letter-spacing: 0.3em;
    font-size: 22px;
    text-align: center;
}

.truss-login-button {
    font: inherit;
    font-size: 15px;
    font-weight: 500;
    color: #ffffff;
    background: var(--truss-blue);
    border: none;
    border-radius: 6px;
    padding: 12px;
    cursor: pointer;
}

.truss-login-button:hover {
    background: #0072db;
}

.truss-login-resend {
    margin-top: 20px;
    text-align: center;
    font-size: 13px;
    color: var(--truss-muted);
}

.truss-login-separator {
    margin: 0 6px;
}

.truss-login-link {
    background: none;
    border: none;
    padding: 0;
    font: inherit;
    font-size: 13px;
    color: var(--truss-blue);
    cursor: pointer;
    text-decoration: none;
}

.truss-login-link:hover {
    text-decoration: underline;
}

/* ---- Create Build ---------------------------------------------------- */

.truss-code {
    font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace;
    font-size: 14px;
    color: var(--truss-muted);
}

.truss-template-table .mud-table-row,
.truss-file-table .mud-table-row {
    height: 37px;
}

.truss-template-row {
    cursor: pointer;
}

.truss-panel {
    border: 1px solid var(--truss-border);
}

.truss-panel-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    background: var(--truss-navy);
    color: #ffffff;
    padding: 8px 8px 8px 16px;
    border-radius: 6px 6px 0 0;
}

.truss-panel-bar .truss-code {
    color: #b9c2d0;
}

.truss-panel-bar .mud-icon-button {
    color: #ffffff;
}

.truss-panel-name {
    font-weight: 500;
}

.truss-options {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.truss-field-label {
    font-size: 13px;
    color: var(--truss-muted);
    margin-bottom: 4px;
}

.truss-required {
    color: #c62828;
    margin-left: 2px;
}

.truss-field-file {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 4px;
}

.truss-field-filename {
    font-weight: 500;
    max-width: 480px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.truss-field-meta {
    font-size: 12px;
    color: var(--truss-muted);
    margin-left: 8px;
}

.truss-tenant-group {
    margin-bottom: 8px;
}

.truss-tenant-group-head {
    display: flex;
    align-items: center;
    gap: 4px;
}

.truss-tenant-list {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
}

.truss-asof {
    max-width: 200px;
}

.truss-name {
    max-width: 480px;
}

.truss-problems {
    margin: 12px 0 0;
    padding-left: 20px;
    color: var(--truss-muted);
    font-size: 13px;
}

.truss-file-dialog .mud-dialog-content {
    position: relative;
    min-height: 420px;
}

/* ---- Tables read a page at a time (My Builds, File Library, Archived) -- */

/* What a table shows while its first page is read: a progress bar over "Loading data...". */
.truss-table-loading {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 8px 0;
    color: var(--truss-muted);
}

/* A date or a row's buttons on one line; the column widens and the name column gives way. */
.truss-nowrap {
    white-space: nowrap;
}

/* ---- My Builds ------------------------------------------------------- */

.truss-status {
    display: inline-flex;
    align-items: center;
    font-size: 13px;
}

.truss-status-completed { color: #2e7d32; }
.truss-status-error { color: #c62828; }
.truss-status-canceled { color: #8a6d00; }
.truss-status-inprogress { color: var(--truss-blue); }

.truss-row-highlight {
    background: rgba(0, 133, 255, 0.08);
}

/* MudBlazor's dense cells pad 16px left and 24px right, so the expander column ends at 60px
   and the status starts at 76px -- right of where the expanded details below it start. Tighten
   both leading cells so the status sits left of the details it labels.
   https://github.com/MudBlazor/MudBlazor/blob/v9.10.0/src/MudBlazor/Styles/components/_table.scss */
.truss-builds-table .mud-table-cell:first-child {
    padding-right: 0;
    padding-inline-end: 0;
}

.truss-builds-table .mud-table-cell:nth-child(2) {
    padding-left: 8px;
    padding-inline-start: 8px;
}

.truss-build-actions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 4px;
    white-space: nowrap;
}

.truss-build-details {
    padding: 12px 16px 12px 56px !important;
    background: var(--truss-bg);
}

.truss-build-template + .truss-build-template {
    margin-top: 12px;
}

.truss-build-template-head {
    margin-bottom: 4px;
}

.truss-build-settings {
    display: grid;
    grid-template-columns: max-content 1fr;
    gap: 2px 16px;
    margin: 0;
    font-size: 13px;
}

.truss-build-settings dt {
    color: var(--truss-muted);
}

.truss-build-settings dd {
    margin: 0;
}

.truss-build-files {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 8px;
    margin-top: 6px;
}

/* ---- Market Database ------------------------------------------------- */

/* From 960px wide the page is the window's height less .truss-page's 24px above and below: the head and search box
   take what they need, and the filters and the table share the rest, each scrolling on its own. Every flex item on
   the way down has min-height: 0, or it would grow to its content and push the page past the window. Below 960px
   (the media query at the end) the page scrolls as a whole. */
.truss-market-page {
    display: flex;
    flex-direction: column;
    height: calc(100vh - 48px);
}

.truss-market-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 16px;
}

.truss-market-search {
    display: flex;
    align-items: center;
    gap: 16px;
    margin-bottom: 12px;
}

.truss-market-search .mud-input-control {
    flex: 1;
}

.truss-market-summary {
    color: var(--truss-muted);
    font-size: 13px;
}

.truss-market-layout {
    flex: 1;
    min-height: 0;
    display: flex;
    gap: 16px;
    align-items: stretch;
}

.truss-market-sidebar {
    width: 260px;
    flex-shrink: 0;
    background: #ffffff;
    border: 1px solid var(--truss-border);
    border-radius: 6px;
    padding: 12px;
    overflow-y: auto;
}

.truss-market-sidebar-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.truss-facet-group {
    margin-top: 12px;
}

.truss-facet {
    display: flex;
    align-items: center;
    font-size: 13px;
    cursor: pointer;
}

.truss-facet .mud-checkbox {
    margin-right: 6px;
}

.truss-facet-value {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.truss-facet-all {
    font-weight: 500;
    border-bottom: 1px solid var(--truss-border);
    margin-bottom: 2px;
}

/* ---- Config ---------------------------------------------------------- */

.truss-market-data-toolbar {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 8px;
}

.truss-market-data-search {
    flex: 1;
}

.truss-market-data-count,
.truss-config-note {
    font-size: 13px;
    color: var(--truss-muted);
    white-space: nowrap;
    margin-left: 8px;
}

/* Config's demo mode start date, start time and hours, side by side while they fit. */
.truss-demo-fields {
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
    max-width: 720px;
}

.truss-demo-fields > * {
    flex: 1 1 200px;
}

.truss-facet-count {
    color: var(--truss-muted);
    font-variant-numeric: tabular-nums;
    margin-left: 8px;
}

.truss-market-results {
    flex: 1;
    min-width: 0;
    min-height: 0;
    display: flex;
    flex-direction: column;
    background: #ffffff;
    border: 1px solid var(--truss-border);
    border-radius: 6px;
}

/* MudTabs renders the tab bar, then .mud-tabs-panels holding only the active panel. */
.truss-market-tabs,
.truss-market-tabs > .mud-tabs-panels,
.truss-market-tabs .mud-tab-panel-active {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
}

.truss-market-results .truss-table-loading {
    padding: 16px;
}

/* The bar a later search shows over the rows. Always 4px tall, so the rows do not move when it appears. */
.truss-market-progress {
    flex: none;
    height: 4px;
}

.truss-market-none {
    flex: 1;
}

.truss-table-scroll {
    flex: 1;
    min-height: 0;
    overflow: auto;
}

/* Each column is the width its <col> gives it, and the table the sum of them (MarketDatabase.razor), as in Excel: text
   that does not fit is cut off, with its full value in the cell's title. */
.truss-market-table {
    table-layout: fixed;
    border-collapse: collapse;
    font-size: 13px;
}

.truss-market-table th {
    position: sticky;
    top: 0;
    background: #ffffff;
    text-align: left;
    font-weight: 500;
    color: var(--truss-muted);
    padding: 0;
    border-bottom: 1px solid var(--truss-border);
    z-index: 1;
}

.truss-market-table td {
    padding: 8px 12px;
    border-bottom: 1px solid #eef0f3;
    vertical-align: top;
}

.truss-market-table td,
.truss-market-table td > div {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.truss-sort-button {
    display: flex;
    align-items: center;
    gap: 2px;
    width: 100%;
    padding: 10px 12px;
    border: 0;
    background: none;
    font: inherit;
    color: inherit;
    text-align: inherit;
    cursor: pointer;
}

.truss-sort-button:hover {
    color: var(--mud-palette-text-primary);
}

.truss-sort-button:focus-visible {
    outline: 2px solid var(--mud-palette-primary);
    outline-offset: -2px;
}

.truss-market-table th.numeric .truss-sort-button {
    justify-content: flex-end;
}

.truss-sort-label {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.truss-sort-icon {
    flex: none;
}

.truss-sort-order {
    flex: none;
    font-size: 11px;
}

/* The right edge of a header, dragged or double-clicked to resize its column (market-columns.js). The header is sticky,
   so it positions the handle. */
.truss-column-resizer {
    position: absolute;
    top: 0;
    right: 0;
    width: 7px;
    height: 100%;
    cursor: col-resize;
    touch-action: none;
}

.truss-column-resizer::after {
    content: "";
    position: absolute;
    top: 25%;
    right: 3px;
    width: 1px;
    height: 50%;
    background: var(--truss-border);
}

.truss-column-resizer:hover::after,
.truss-column-resizing .truss-column-resizer::after {
    top: 0;
    height: 100%;
    background: var(--mud-palette-primary);
}

body.truss-column-resizing {
    cursor: col-resize;
    user-select: none;
}

.truss-market-table tbody tr:nth-child(even) td {
    background: #f6f7f9;
}

.truss-market-table .numeric {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

.truss-market-table .secondary {
    color: var(--truss-muted);
    font-size: 12px;
}

.truss-market-footer {
    flex: none;
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 8px 12px;
    border-top: 1px solid var(--truss-border);
}

@media (max-width: 959.98px) {
    .truss-market-page {
        height: auto;
    }

    .truss-market-layout {
        flex-direction: column;
    }

    .truss-market-sidebar {
        width: 100%;
    }

    .truss-table-scroll {
        flex: none;
        max-height: 70vh;
    }

    .truss-market-search {
        flex-direction: column;
        align-items: stretch;
        gap: 4px;
    }
}

/* ---- Connection lost --------------------------------------------------- */
/* Two dialogs declared in App.razor, shown when the Blazor circuit is gone: the reconnection modal while
   Blazor retries, and the error UI when an unhandled exception ended the circuit for good. Blazor drives
   both from JavaScript; everything here keys off the classes and inline styles it sets. Names and states:
   https://learn.microsoft.com/en-us/aspnet/core/blazor/fundamentals/signalr?view=aspnetcore-10.0#reflect-the-server-side-connection-state-in-the-ui

   MudBlazor 9.10.0 ships the Blazor template's own styles for both of these elements, so this is a fight
   over the cascade and every rule below is written to win it. Measured in a browser, not assumed:

     #components-reconnect-modal { z-index: 9999 !important;
                                   background-color: var(--mud-palette-background) !important }
     #components-reconnect-modal button { text-transform: uppercase; border-radius: ...;
                                          margin: 40px auto !important }
     #blazor-error-ui { position: fixed; bottom: 0; width: 100%; padding: .6rem ... }
     #blazor-error-ui .reload { color: inherit; text-decoration: underline }
     .dismiss { position: absolute; right: .75rem; top: .5rem }   <- not even scoped to the dialog

   Consequences, in order: the backdrop came out fully transparent, because the Mud palette variable is
   unset on the pages that use LoginLayout (no MudThemeProvider) and an unset var makes the whole
   declaration invalid; the buttons came out uppercase, square and 40px adrift; and a link marked
   "dismiss" was thrown to the top-right corner of the window. So: every rule is scoped to the element id
   to beat MudBlazor's id-scoped rules on source order (app.css is linked after MudBlazor.min.css), and
   !important appears exactly where MudBlazor used it. */

#components-reconnect-modal,
#blazor-error-ui {
    display: none;
    position: fixed;
    inset: 0;

    /* Both !important only because MudBlazor's own rule for the reconnection modal is. 9999 is the value
       it forces there, kept for the other dialog so the two behave alike; either way it is above every
       MudBlazor layer (its highest is --mud-zindex-tooltip). */
    background-color: rgba(10, 25, 49, 0.55) !important;
    z-index: 9999 !important;
}

/* Shown while Blazor is retrying, and left up when it gives up. components-reconnect-hide is the class it
   sets once the connection is back, and is deliberately absent from this list. Blazor makes the error UI
   visible by setting display: block inline instead, which no stylesheet rule can undo, so the card below
   is centered in a way that does not care which of the two it is sitting in. */
#components-reconnect-modal.components-reconnect-show,
#components-reconnect-modal.components-reconnect-retrying,
#components-reconnect-modal.components-reconnect-paused,
#components-reconnect-modal.components-reconnect-failed,
#components-reconnect-modal.components-reconnect-rejected {
    display: block;
}

#components-reconnect-modal .truss-connection-card,
#blazor-error-ui .truss-connection-card {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: calc(100% - 32px);
    max-width: 420px;
    box-sizing: border-box;

    background: #ffffff;
    border-radius: 6px;
    box-shadow: 0 8px 32px rgba(10, 25, 49, 0.35);
    padding: 28px 32px;
    text-align: center;
}

#components-reconnect-modal .truss-connection-title,
#blazor-error-ui .truss-connection-title {
    font-size: 20px;
    font-weight: 500;
    margin: 0 0 8px;
    color: var(--truss-text);
}

#components-reconnect-modal .truss-connection-text,
#blazor-error-ui .truss-connection-text {
    color: var(--truss-muted);
    font-size: 14px;
    line-height: 1.5;
    margin: 0 0 20px;
}

#components-reconnect-modal .truss-connection-actions,
#blazor-error-ui .truss-connection-actions {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
}

#components-reconnect-modal .truss-connection-button,
#blazor-error-ui .truss-connection-button {
    font: inherit;
    font-size: 15px;
    font-weight: 500;
    text-transform: none;
    letter-spacing: normal;
    color: #ffffff;
    background-color: var(--truss-blue);
    border: none;
    border-radius: 6px;
    padding: 12px 24px;
    cursor: pointer;
    text-decoration: none;

    /* MudBlazor puts margin: 40px auto !important on every button in the reconnection modal. */
    margin: 0 !important;
}

#components-reconnect-modal .truss-connection-button:hover,
#blazor-error-ui .truss-connection-button:hover {
    background-color: #0072db;
}

#components-reconnect-modal .truss-connection-button:disabled {
    opacity: 0.6;
    cursor: default;
}

#components-reconnect-modal .truss-connection-link,
#blazor-error-ui .truss-connection-link {
    font-size: 13px;
    color: var(--truss-blue);
    text-decoration: none;
    cursor: pointer;
}

#components-reconnect-modal .truss-connection-link:hover,
#blazor-error-ui .truss-connection-link:hover {
    text-decoration: underline;
}

/* One card, three sets of words. Everything is hidden until the state class on the modal picks a set, so a
   state Blazor adds in some later version shows the card with no text rather than the wrong text. */
#components-reconnect-modal .truss-connection-when-retrying,
#components-reconnect-modal .truss-connection-when-failed,
#components-reconnect-modal .truss-connection-when-rejected {
    display: none;
}

#components-reconnect-modal.components-reconnect-show .truss-connection-when-retrying,
#components-reconnect-modal.components-reconnect-retrying .truss-connection-when-retrying,
#components-reconnect-modal.components-reconnect-paused .truss-connection-when-retrying,
#components-reconnect-modal.components-reconnect-failed .truss-connection-when-failed,
#components-reconnect-modal.components-reconnect-rejected .truss-connection-when-rejected {
    display: block;
}

#components-reconnect-modal.components-reconnect-failed .truss-connection-actions.truss-connection-when-failed,
#components-reconnect-modal.components-reconnect-rejected .truss-connection-actions.truss-connection-when-rejected {
    display: flex;
}
