/* FluentUI's own design tokens (--design-unit, --neutral-*, etc.) are only ever populated by
   FAST's DesignToken.setValueFor() being called against :root/body - <FluentDesignTheme> (see
   App.razor) sets the light/dark mode and body[data-theme], but never actually calls that for the
   base spacing/color tokens in this setup, so every var(--design-unit)/var(--neutral-*) reference
   below and throughout the FluentUI component CSS resolves to nothing. Confirmed by inspecting
   document.adoptedStyleSheets directly: the ":root {}" rule FluentUI reserves for these tokens
   stays empty. Most of the app "looks right" anyway by accident (a transparent body over the
   browser's white canvas, with default black text, happens to resemble a light theme) - the
   FluentDialog panel is what actually exposed this, since a fully transparent, zero-padding panel
   is visually obvious in a way a transparent page background isn't. Hardcoded fallbacks here and
   on fluent-dialog::part(control) below fix both directly rather than depending on token
   resolution that isn't happening. */
html,
body {
    margin: 0;
    min-height: 100%;
    font-family: "Segoe UI", Arial, sans-serif;
    background: var(--neutral-layer-1, #f5f5f5);
    color: var(--neutral-foreground-rest, #242424);
}

/* Setting --dialog-padding at :root (so it flows through the normal inheritance chain) does NOT
   work here: FluentUI's own internal styles reset it again somewhere between :root and these
   elements (confirmed by inspecting getComputedStyle(...).getPropertyValue('--dialog-padding') on
   the header element directly - empty, despite being non-empty on :root itself), and separately,
   an *invalid* var()-derived value (still-unresolved --design-unit) computes to the property's
   initial value rather than falling back to any lower-priority rule, so it can't be out-cascaded
   by specificity/order either. Setting `padding` directly with !important on each of FluentUI's
   own selectors sidesteps both problems - guaranteed to win regardless of whatever the library's
   internal cascade is doing, without needing to understand or repair its token-resolution chain. */
fluent-dialog::part(control) {
    padding: 24px !important;
    background-color: #ffffff;
    border-radius: 8px;
    box-shadow: 0 6.4px 14.4px rgba(0, 0, 0, 0.18), 0 1.2px 3.6px rgba(0, 0, 0, 0.11);
}

.fluent-dialog-header {
    padding: 0 0 24px 0 !important;
}

.fluent-dialog-footer {
    padding: 24px 0 0 0 !important;
}

a {
    color: var(--accent-foreground-rest);
    text-decoration: none;
}

a:hover {
    text-decoration: underline;
}

button {
    font: inherit;
}

#app {
    min-height: 100vh;
}

.shell {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
}

.shell-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
    padding: 1rem 1.25rem;
    border-bottom: 1px solid var(--neutral-stroke-divider-rest);
    background: var(--neutral-layer-2);
    position: sticky;
    top: 0;
    z-index: 10;
}

.shell-brand-text h1 {
    margin: 0;
    font-size: 1.35rem;
}

.shell-brand-text p {
    margin: 0.15rem 0 0;
    color: var(--neutral-foreground-hint);
    font-size: 0.95rem;
}

.shell-body {
    display: flex;
    flex: 1;
    min-height: 0;
}

.shell-nav {
    width: 280px;
    flex-shrink: 0;
    border-right: 1px solid var(--neutral-stroke-divider-rest);
    background: var(--neutral-layer-2);
    padding: 0.75rem;
    overflow: hidden;
    transition: width 0.15s ease;
}

.shell-nav.shell-nav-collapsed {
    width: 56px;
}

.shell-main {
    flex: 1;
    min-width: 0;
    padding: 1.25rem;
}

.login-display {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    flex-wrap: wrap;
    justify-content: flex-end;
}

.login-display-name {
    color: var(--neutral-foreground-hint);
    font-size: 0.95rem;
}

.page-header {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 1rem;
    margin-bottom: 1rem;
    flex-wrap: wrap;
}

.page-header h1 {
    margin: 0;
    font-size: 1.9rem;
}

.page-header p {
    margin: 0.35rem 0 0;
    color: var(--neutral-foreground-hint);
}

.stats-grid,
.summary-grid,
.detail-grid,
.form-grid {
    display: grid;
    gap: 1rem;
}

.stats-grid {
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    margin-bottom: 1rem;
}

.summary-grid,
.detail-grid,
.form-grid {
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
}

.stat-card,
.section-card,
.detail-card,
.empty-card,
.loading-card,
.error-card {
    padding: 1rem;
    /* FluentCard's Shadow DOM defaults to height: var(--card-height, 100%), so inside a flex
       ancestor with a definite height (.shell-body's stretch) it fills all available vertical
       space instead of sizing to its content. --card-height is the component's own override
       point for this - forcing it to "auto" here restores normal content-driven sizing. */
    --card-height: auto;
}

.stat-card-label,
.detail-label,
.section-heading {
    color: var(--neutral-foreground-hint);
}

.stat-card-value {
    font-size: 1.8rem;
    font-weight: 600;
    margin-top: 0.35rem;
}

.stat-card-description {
    margin-top: 0.35rem;
    font-size: 0.95rem;
    color: var(--neutral-foreground-hint);
}

.section-card,
.detail-card {
    margin-bottom: 1rem;
}

.section-heading {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
    margin-bottom: 0.75rem;
    font-weight: 600;
}

.table-wrapper {
    overflow-x: auto;
    /* overflow-x also clips vertically, so leave room for an open column filter popup even when the list is short or empty. */
    min-height: 24rem;
}

.table-wrapper .fluent-data-grid {
    width: 100%;
}

/* FilterableGrid's row popup: the row's actions as a short stack of full-width buttons. */
.row-popup {
    --dialog-width: 340px;
    --dialog-height: auto;
}

/* fluent-card's "contain: content" and "content-visibility: auto" both make it the containing block for
   the dialog's fixed positioning - the popup and its overlay would be centred on the card instead of
   the viewport. */
fluent-card:has(.row-popup) {
    contain: none;
    content-visibility: visible;
}

/* The same containment also clips an open select's listbox to the card, which on a short card like the
   Settings page leaves only the first option or two visible. */
.settings-card {
    contain: none;
    content-visibility: visible;
}

.row-popup-actions {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.row-popup-actions fluent-button {
    width: 100%;
}

.clickable-row {
    cursor: pointer;
    border-bottom: 1px solid var(--neutral-stroke-divider-rest);
}

.clickable-row:hover {
    background-color: var(--neutral-fill-secondary-rest, rgba(0, 0, 0, 0.06));
}

.stat-card-value-good {
    color: #166534;
}

.stat-card-value-caution {
    color: #92400e;
}

.stat-card-value-critical {
    color: #991b1b;
}

.stat-card-clickable {
    cursor: pointer;
}

.toolbar {
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
    margin-bottom: 0.75rem;
    align-items: center;
}

.toolbar-spacer {
    flex: 1 1 auto;
}

.search-field {
    width: 100%;
    max-width: 320px;
}

.filter-field {
    width: 100%;
    max-width: 260px;
}

/* Under a FilterableGrid: "Reset column widths" on the left (only once widths were changed), paging on the right. */
.grid-footer {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin-top: 0.75rem;
}

.grid-footer-paginator {
    margin-left: auto;
}

.breadcrumbs ol {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.35rem;
    list-style: none;
    margin: 0 0 0.75rem;
    padding: 0;
    font-size: 0.9rem;
    color: var(--neutral-foreground-hint, #616161);
}

/* Chevron separator drawn with borders, so there's no glyph that depends on font or file encoding. */
.breadcrumbs li + li::before {
    content: "";
    display: inline-block;
    width: 0.4em;
    height: 0.4em;
    margin: 0 0.45rem 0.1em 0.1rem;
    border-top: 1.5px solid currentColor;
    border-right: 1.5px solid currentColor;
    transform: rotate(45deg);
    opacity: 0.7;
}

/* The list trail sits directly above a detail page's own trail. */
.breadcrumbs-lists ol {
    margin-bottom: 0.25rem;
    font-size: 0.8rem;
}

.breadcrumbs [aria-current="page"] {
    color: var(--neutral-foreground-rest, #242424);
    font-weight: 600;
}

.column-filter {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    min-width: 220px;
    max-width: 320px;
    font-weight: normal;
}

.column-filter-options {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    max-height: 220px;
    overflow-y: auto;
}

.column-filter-date {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
}

.column-filter-date input {
    font: inherit;
    padding: 0.2rem 0.35rem;
    border: 1px solid var(--neutral-stroke-rest, #d1d1d1);
    border-radius: 4px;
}

.column-filter-actions {
    display: flex;
    justify-content: flex-end;
}

.grid-empty {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    padding: 1rem;
    color: var(--neutral-foreground-hint, #616161);
}

/* Tags: solid chips for an object's own tags, outlined ones for tags inherited from a parent. */
.tag-chips {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.25rem;
    vertical-align: middle;
}

.tag-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.2rem;
    max-width: 14rem;
    padding: 0.05rem 0.5rem;
    border: 1px solid var(--tag-color, #64748b);
    border-radius: 999px;
    background: var(--tag-color, #64748b);
    color: #fff;
    font-size: 0.8rem;
    line-height: 1.3;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.tag-chip-inherited {
    background: transparent;
    color: var(--tag-color, #64748b);
    border-style: dashed;
}

/* The grids clip cells to one line; let a row's chips stay on that line and cut off at the cell edge. */
.fluent-data-grid td .tag-chips {
    flex-wrap: nowrap;
}

.tag-chip-remove {
    border: none;
    background: none;
    color: inherit;
    cursor: pointer;
    padding: 0 0 0 0.15rem;
    font-size: 0.95rem;
    line-height: 1;
}

.tag-picker {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}

.tag-picker-input {
    min-width: 10rem;
    flex: 1 1 10rem;
    font: inherit;
    padding: 0.25rem 0.5rem;
    border: 1px solid var(--neutral-stroke-rest, #d1d1d1);
    border-radius: 4px;
    background: var(--neutral-fill-input-rest, #fff);
    color: var(--neutral-foreground-rest, #242424);
}

.tag-picker-inherited {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.85rem;
}

.tag-color-field {
    display: flex;
    align-items: center;
    gap: 0.75rem;
}

.tag-color-field input[type="color"] {
    width: 2.5rem;
    height: 2rem;
    padding: 0;
    border: 1px solid var(--neutral-stroke-rest, #d1d1d1);
    border-radius: 4px;
    background: none;
    cursor: pointer;
}

.button-row {
    display: flex;
    gap: 0.75rem;
    flex-wrap: wrap;
    margin-top: 1rem;
}

.edit-table {
    width: 100%;
    border-collapse: collapse;
    table-layout: fixed;
    margin-bottom: 0.5rem;
}

.edit-table th {
    text-align: left;
    padding: 0.4rem 0.75rem;
    font-weight: 600;
    font-size: 0.9rem;
    color: var(--neutral-foreground-hint);
    border-bottom: 1px solid var(--neutral-stroke-divider-rest);
}

.edit-table td {
    padding: 0.4rem 0.75rem;
    border-bottom: 1px solid var(--neutral-stroke-divider-rest);
    vertical-align: middle;
}

.edit-table tbody tr:last-child td {
    border-bottom: none;
}

/* Free-text columns (Key/Value, cron expression, ...) are left unset so they share the remaining
   space evenly under table-layout: fixed. Narrow columns (a switch, a type select, ...) opt into a
   fixed width explicitly - column count/position varies per table, so this can't rely on nth-child. */
.edit-table th.edit-table-narrow,
.edit-table td.edit-table-narrow {
    width: 170px;
}

.edit-table th:last-child,
.edit-table td:last-child {
    width: 90px;
    white-space: nowrap;
}

.edit-table-input {
    width: 100%;
}

.parameter-table {
    width: 100%;
    border-collapse: collapse;
    margin-bottom: 0.5rem;
}

.parameter-table th {
    text-align: left;
    padding: 0.4rem 0.75rem;
    font-weight: 600;
    font-size: 0.9rem;
    color: var(--neutral-foreground-hint);
    border-bottom: 1px solid var(--neutral-stroke-divider-rest);
}

.parameter-table td {
    padding: 0.4rem 0.75rem;
    border-bottom: 1px solid var(--neutral-stroke-divider-rest);
    vertical-align: middle;
}

.parameter-table tbody tr:last-child td {
    border-bottom: none;
}

.parameter-table th.parameter-table-name,
.parameter-table td.parameter-table-name {
    text-align: right;
}

.inline-note,
.muted {
    color: var(--neutral-foreground-hint);
}

.detail-value {
    margin-top: 0.35rem;
    font-weight: 500;
    word-break: break-word;
}

.parameter-list,
.log-list,
.drill-down-list {
    list-style: none;
    padding: 0;
    margin: 0;
}

.parameter-list li,
.log-list li {
    padding: 0.65rem 0;
    border-bottom: 1px solid var(--neutral-stroke-divider-rest);
}

.parameter-list li:last-child,
.log-list li:last-child {
    border-bottom: none;
}

.drill-down-list li {
    padding: 0.65rem 0.5rem;
    border-bottom: 1px solid var(--neutral-stroke-divider-rest);
}

.drill-down-list li:last-child {
    border-bottom: none;
}

.drill-down-item {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
}

.drill-down-item-title {
    font-weight: 600;
}

.log-entry {
    display: flex;
    gap: 0.75rem;
    align-items: flex-start;
}

.log-entry-header {
    display: flex;
    flex-wrap: nowrap;
    gap: 0.5rem;
    align-items: center;
    flex-shrink: 0;
    min-width: 200px;
}

.log-body {
    flex: 1;
    min-width: 0;
}

.log-message {
    white-space: pre-wrap;
    word-break: break-word;
}

.log-exception,
.detail-value-error {
    white-space: pre-wrap;
    word-break: break-word;
    font-family: var(--body-font, monospace);
    color: #991b1b;
}

.log-exception {
    margin-top: 0.35rem;
    font-size: 0.9rem;
}

.run-progress {
    display: grid;
    gap: 0.5rem;
}

.loading-card,
.error-card,
.empty-card {
    display: grid;
    gap: 0.75rem;
    justify-items: start;
}

.loading-card {
    justify-items: center;
}

.badge-stack {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

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

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

.loading-progress {
    position: absolute;
    display: block;
    width: 8rem;
    height: 8rem;
    inset: 20vh 0 auto 0;
    margin: 0 auto;
}

.loading-progress circle {
    fill: none;
    stroke: #e0e0e0;
    stroke-width: 0.6rem;
    transform-origin: 50% 50%;
    transform: rotate(-90deg);
}

.loading-progress circle:last-child {
    stroke: #1b6ec2;
    stroke-dasharray: calc(3.141 * var(--blazor-load-percentage, 0%) * 0.8), 500%;
    transition: stroke-dasharray 0.05s ease-in-out;
}

.loading-progress-text {
    position: absolute;
    text-align: center;
    font-weight: bold;
    inset: calc(20vh + 3.25rem) 0 auto 0.2rem;
}

.loading-progress-text:after {
    content: var(--blazor-load-percentage-text, "Loading");
}

@media (max-width: 900px) {
    .shell-body {
        flex-direction: column;
    }

    .shell-nav {
        width: auto;
        border-right: none;
        border-bottom: 1px solid var(--neutral-stroke-divider-rest);
        padding: 0.5rem 1rem 1rem;
    }

    .shell-main {
        padding: 1rem;
    }
}

@media (max-width: 640px) {
    .shell-header {
        align-items: flex-start;
        flex-direction: column;
    }

    .page-header h1 {
        font-size: 1.55rem;
    }

    .stats-grid,
    .summary-grid,
    .detail-grid,
    .form-grid {
        grid-template-columns: 1fr;
    }
}

.schedule-row {
    align-items: end;
    padding-bottom: 0.75rem;
    margin-bottom: 0.75rem;
    border-bottom: 1px solid var(--neutral-stroke-divider-rest);
}

/* Two-column label:field form layout, ported from WestfraserGenkRisicoAnalyse
   (src/Gra.Ui/wwwroot/css/app.css) for dialog forms. */
.ra-label-input-grid {
    display: grid;
    grid-template-columns: 180px 1fr;
    column-gap: 16px;
    row-gap: 15px;
    align-items: center;
}

.ra-label-input-grid .ra-field-label {
    justify-self: end;
    text-align: right;
}

.ra-label-input-grid .ra-grid-full-row {
    grid-column: 1 / -1;
}

/* Let a FluentSelect's closed value wrap onto extra lines instead of being
   clipped by the control's fixed single-line height - only grows taller when
   the selected text actually needs to wrap. */
.gra-select-wrap::part(control) {
    height: auto !important;
    min-height: 32px;
    padding-block: 6px;
}

.gra-select-wrap::part(selected-value) {
    white-space: normal !important;
    overflow-wrap: anywhere;
    line-height: 1.3;
}

/* Let the open popup grow wider than the (deliberately narrow) closed control,
   so options are readable without wrapping/ellipsis while browsing the list. */
.gra-select-wrap::part(listbox) {
    width: max-content !important;
    min-width: 100%;
    max-width: min(90vw, 480px);
}

/* FluentLabel has no built-in Required indicator (unlike FluentTextField/FluentSelect,
   which render one via their own Label parameter) - used for grid-layout forms where the
   label is a standalone element next to the input, not passed via a component's Label=. */
.gra-required-marker {
    color: #C50F1F;
}

/* Required-field indicators: FluentUI's built-in required-asterisk already renders using
   the "--error" design token (confirmed red, independent of the app's custom accent color),
   so Required="true" on Fluent inputs needs no extra styling here. This outline class flags
   fields that are currently empty/incomplete. */
.gra-field-invalid {
    outline: 2px solid #C50F1F;
    outline-offset: 1px;
    border-radius: 4px;
}

/* While an invalid field is focused, the focus state should read as clearly
   as it does on a valid field - swap the outline to the same neutral color
   used for normal focus instead of letting the red invalid outline win. It
   reverts to red on blur so the invalid state is still visible when you tab away. */
.gra-field-invalid:focus-within {
    outline-color: black;
}

/* Subtle background highlight for the currently focused dropdown, in
   addition to its outline. Overrides the full `background` shorthand, not
   just background-color - FluentUI's own .control rule paints an opaque
   background-image (a same-color gradient) on top of background-color,
   which would otherwise hide a background-color-only override. */
.gra-select-wrap:focus-within::part(control) {
    background: var(--neutral-fill-secondary-rest, rgba(0, 0, 0, 0.06)) !important;
}

