﻿:root {

    /* button */
    --yellax-button-color: white;
    --yellax-button-background: var(--button-color-primary); /* Yellax Blue */
    /* Flow step */
    --yellax-flowstep-active-color: black;
    --yellax-flowstep-active-background: #FFD100; /* yellax yellow */
    --yellax-flowstep-lowprio-color: white;
    --yellax-flowstep-lowprio-background: #666666; /* dark gray */
    --yellax-flowstep-disabled-color: gray;
    --yellax-flowstep-disabled-background: #d5d5d5; /* light gray */

    /* Layout chrome — the top bar and sidebar sizes. Global because both the layout itself
       and the components living inside the bar (triggers, logo plate) are sized from them. */
    --topbar-height: 3.125rem;
    --topbar-logo-height: 2.125rem;

    /* The maintenance bar above the top bar. Its height is a value of its own, so the top bar
       keeps meaning only the top bar: adding the maintenance bar into --topbar-height would
       make the top bar itself taller. The offset is what everything measured from the top of
       the viewport subtracts; it stays zero until the layout holds a bar (rule below). */
    --maintenance-bar-height: 2.25rem;
    --maintenance-bar-offset: 0rem;

    /* The project menu's width, and the floor under its trigger in the bar. One value for both:
       the trigger is what opens the panel, so a panel wider than its trigger reads as a stray
       block hanging off the name. Keeping them apart is what let the trigger shrink to a sliver
       while the panel stayed put. */
    --project-menu-width: 16rem;

    /* Overridable menu-strip width: the collapsed root marking below overrides this one
       variable, which is why the sidebar, the brand plate on a page with a menu, and the
       content margin all narrow together from a single toggle. */
    --sidebar-width: 12.375rem;

    /* Fixed at the expanded size, never overridden by the collapsed marking. The brand
       plate on a page without a sidebar reads this one instead, so it keeps its normal
       width regardless of the stored collapse preference — that page has no menu to line
       up with. */
    --sidebar-width-expanded: 12.375rem;
    --sidebar-width-collapsed: 3.5rem;

    /* One text size and one icon size for everything in the top bar. */
    --topbar-font-size: var(--text-size-medium);
    --topbar-icon-size: 1.125rem;

    /* Shared height for the pill-shaped items in the bar (environment chip, job status),
       so they line up with each other instead of each floating at its own size. */
    --topbar-chip-height: 2rem;

    --topbar-divider-width: 3px;

    /* Overlays for the bar: they are translucent, so one set works on every
       environment colour instead of a variant per colour. */
    --topbar-divider: rgb(255 255 255 / 30%);
    --topbar-chip-bg: rgb(255 255 255 / 14%);
    --topbar-chip-border: rgb(255 255 255 / 22%);
    --topbar-trigger-active-bg: rgb(0 0 0 / 18%);
    --topbar-focus-ring: rgb(255 255 255 / 70%);

    /* Top-bar trigger hover — grey-900 at 30% opacity */
    --topbar-trigger-hover-bg: color-mix(in srgb, var(--grey-900) 30%, transparent);

    /* Grid — height budget for the .grid-viewport-height fallback */
    --grid-viewport-height-offset: 20rem;

    /* Bootstrap draws body text from its own variable; point it at the interface font so a
       component that reads it directly does not fall back to the Bootstrap stack. */
    --bs-body-font-family: var(--font-ui);
}

/* The collapsed state is server-rendered onto the root element from a cookie (see
   App.razor), so this rule is already in effect on the very first response — nothing here
   waits for script to run after the page loads. */
:root[data-sidebar-collapsed="true"] {
    --sidebar-width: var(--sidebar-width-collapsed);
}

/* The offset is set on the layout root rather than on the bar, because the fixed sidebar and
   the page content are the bar's siblings, not its children. Only while the bar is rendered:
   when there is nothing to announce the bar renders no element at all, so the offset falls
   back to zero without anything having to re-render the layout. */
.main-layout:has(> .maintenance-bar) {
    --maintenance-bar-offset: var(--maintenance-bar-height);
}

.icon-waiting {
    color: var(--blue-700);
}

.icon-processing {
    color: var(--blue-700);
}

.icon-completed {
    color: var(--status-valid-fg);
}

.icon-unknown {
    color: var(--blue-700);
}

.icon-crashed {
    color: var(--red-500);
}

.field-type-icon-frame {
    box-sizing: border-box;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.1rem;
    height: 1.1rem;
    padding: 0.1rem 0 0 0;
    line-height: 1;
    border: 0.0625rem solid black;
    background-color: transparent;
    font-size: 0.7rem;
    vertical-align: middle;
}

/* The design's body size, set on body rather than on html: every rem in the stylesheets is
   relative to the root, so scaling the root would shrink the whole interface instead of
   only the text that has no size of its own. */
html, body {
    font-family: var(--font-ui);
}

body {
    font-size: var(--text-size-medium);
    line-height: var(--text-size-medium-lh);
}

a, .btn-link {
    color: var(--accent-color);
}

a:hover, .btn-link:hover {
    color: var(--blue-800);
}

.btn-primary {
    color: #fff;
    background-color: var(--button-color-primary);
    border-color: var(--button-color-primary);
}

.btn-primary:hover {
    background-color: var(--button-color-primary-hover);
    border-color: var(--button-color-primary-hover);
}

.btn-primary:focus {
    background-color: var(--button-color-primary);
    border-color: var(--button-color-primary-hover);
}

.btn-primary:active {
    background-color: var(--button-color-primary-onclick);
    border-color: var(--button-color-primary-onclick);
}

.dropdown-item.active, .dropdown-item:active {
    color: #fff;
    background-color: var(--button-color-primary);
}

.form-control:focus {
    border-color: var(--blue-500);
}

.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
  box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem var(--blue-500);
}

.alert-info {
    color: var(--blue-800);
    background-color: var(--blue-50);
    border-color: var(--blue-100);
}

.content {
    padding-top: 1.1rem;
}

h1:focus {
    outline: none;
}

.valid.modified:not([type=checkbox]) {
    outline: 1px solid #26b050;
}

.invalid {
    outline: 1px solid #e50000;
}

.validation-message {
    color: #e50000;
}

.blazor-error-boundary {
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
    padding: 1rem 1rem 1rem 3.7rem;
    color: white;
}

.blazor-error-boundary::after {
    content: "An error has occurred."
}

.darker-border-checkbox.form-check-input {
    border-color: #929292;
}

.inactive-row {
    color: var(--grey-500) !important;
}

/* Not the same treatment as .inactive-row: grey means inactive on this page, and a layer still
   being built is neither. The status indicator already explains the state; this only marks the
   row as unavailable. cursor is set here because `inert` only blocks interaction, not rendering -
   MDN: it does not by itself cause any visual change. */
.layer-row-in-progress {
    background-color: var(--orange-50) !important;
    cursor: not-allowed;
}

.error-cell {
    background-color: var(--status-invalid-bg) !important;
    color: var(--status-invalid-fg) !important;
}

.selected-cell {
    background-color: var(--blue-100) !important;
}

.user-cell:hover {
    cursor: pointer;
}

/* Layer history tool only, on user-column cells: the dotted underline that says a cell has
   history to click through, matching the prototype's cell-marking style
   (.claude/docs/design/datacontrol/ui/viewpointdata.jsx:576). A separate class from
   .selected-cell above - that one still styles the Data columns page's own history popup grid
   (LayerHistoryPopupGrid.razor), which this story does not touch. */
.history-capable-cell {
    border-bottom: 1px dotted var(--blue-500);
}

.history-selected-cell {
    background-color: var(--blue-100) !important;
    outline: 1px solid var(--blue-500);
    border-radius: 0.125rem;
    font-weight: 600;
}

.required-caption:after {
    content: ' *';
    color: red;
}

/* A fixed column is marked by the shadow below, not by a fill: a #999 block behind the header
   text was the darkest thing on the page and it read as a selection rather than as "this column
   stays put". The class stays applied by the pages so a later, lighter marker (the design uses a
   pin glyph) has somewhere to land. */

/* The boundary of the frozen band, on the cell DevExpress already marks as the last fixed one.
   With GridDefaults.GridlinesVisible = Horizontal the theme's own border on this cell goes
   transparent, so this shadow is what separates the band from the scrolling columns - the same
   2px 0 3px -2px as the design. */
.dxbl-grid .dxbl-grid-table > thead > tr > th.dxbl-grid-last-fixed-left-cell,
.dxbl-grid .dxbl-grid-table > tbody > tr > td.dxbl-grid-last-fixed-left-cell {
    box-shadow: 2px 0 3px -2px rgba(0, 0, 0, 0.18);
}

/* The pin glyph promised by the comment above, shown before a fixed column's own caption via
   DxGridColumn.HeaderCaptionTemplate - the same marker already used for a fixed column in the
   column overview, the manage-columns view and the column editor (Icon.State.IsFixedColumn). */
.fixed-column-header-pin {
    margin-right: 0.25rem;
    color: var(--accent-color);
}

.inactive-data {
    color: var(--grey-500) !important;
}

.unchanged-value {
    background-color: var(--white) !important;
}

.changed-value {
    background-color: var(--blue-100) !important;
}

.upper-layer {
    background-color: var(--green-300) !important;
}

.lower-layer {
    background-color: var(--orange-300) !important;
}

.warning-indication-cell {
    background-color: var(--yellow-200) !important;
}

.success-indication-cell {
    background-color: var(--green-300) !important;
}

.data-column-header-inactive {
    color: var(--grey-200) !important;
}

.column-bold-text {
    font-weight: bold;
}

/* Fonts */
.title-font {
    font-size: var(--text-size-title);
    line-height: var(--text-size-extralarge-lh);
    font-weight: 700;
    color: var(--text-primary);
    margin: 0.9375rem 0 0.625rem var(--spacing-page-title-indent);
    text-decoration: none;
    min-width: 12.5rem;
}

.title-bar {
    display: flex;
    justify-content: space-between;
    align-items: center;
}

/* Pages */
.page-content {
    margin-left: 1.25rem;
    margin-right: 1.25rem;
}

.header-content {
    display: flex;
    justify-content: space-between;
    align-items: center;
}

.body-content {
    margin-top: 0.25rem;
}

/* The optional row between the page header and the grid: search box, bulk action, row count.
   Defined once so the distance between header and grid is the same on every overview page - a
   page may change how its own items are spread (gap, justify-content), never the margins. */
.grid-toolbar {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    margin: 0 0 0.25rem;
}

/* A toolbar that holds nothing but the row count and the links trailing it puts the whole row on the
   right. Every overview that does so said it in its own stylesheet until they were pulled together here. */
.grid-toolbar-right {
    justify-content: flex-end;
}

/* Bounded-height grid layout. A virtual-scrolling grid needs an upper bound: without one
   it grows to fit every row and the page scrolls instead of the grid. Opt-in, so pages
   without a grid keep their document-flow layout: put .page-fill on the page root and
   .fill-region on every wrapper between that root and the grid. Skip one and the chain
   breaks, leaving the grid unbounded again.
   https://docs.devexpress.com/Blazor/404753/components/grid/paging-and-scrolling/scrolling */
.page-fill {
    display: flex;
    flex-direction: column;
    height: 100%;
    box-sizing: border-box;
}

.fill-region {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
}

/* Sizes to its rows and stops at the height the page has left, so a grid with few rows
   does not leave an empty stretch below them. */
.scrollable-grid {
    flex: 0 1 auto;
    min-height: 0;
    max-height: 100%;
    margin-bottom: 0.5rem;
}

/* Fallback for a grid nested inside third-party markup that cannot carry .fill-region
   (a DevExpress tab panel or loading panel), which breaks the flex chain. */
.grid-viewport-height {
    max-height: calc(100vh - var(--grid-viewport-height-offset) - var(--maintenance-bar-offset));
}

/* One row height for every YxGrid. Measured in the running app: a row carrying the row-action
   button is 32.4px, a row with plain text only 29.8px - so the grids without a row menu (Deliveries,
   Schema Store, the component breakdown on a Delivery) read as denser than the rest. `height` on a
   table row acts as a minimum, so a row whose content really is taller still grows. Group rows keep
   their own, tighter height. */
.yx-grid-fill tbody tr:not(.dxbl-grid-group-row),
.yx-grid-compact tbody tr:not(.dxbl-grid-group-row) {
    height: 2.025rem;
}

.btn-header-group {
    top: 0.625rem;
}

.clickable-cell-button {
    display: flex;
    justify-content: space-between;
    align-items: center;
}

/* The clickable name cell of an overview grid. Row height in a DevExpress grid follows the tallest
   cell, and this cell is the only one holding more than plain text, so both the text and the row
   action button are kept to one text line - otherwise every row is taller than the rows of the data
   grids, which show plain text only.

   The hover highlight still covers the full row: pad by the cell's own --dxbl-grid-text-cell-padding-y
   and cancel it again with a negative margin, so the highlight paints over the cell padding without
   adding to the row height. The DevExpress theme uses the same trick for .dxbl-grid-header-content.

   The text takes the room left next to the button, so the highlight follows a column resize, and a
   value that does not fit ends in an ellipsis instead of wrapping onto a second line - which would
   grow the row again. Give the span a title attribute so the full value stays readable. */
.clickable-text {
    flex: 1;
    min-width: 0;
    margin-block: calc(var(--dxbl-grid-text-cell-padding-y, 0.25rem) * -1);
    padding: var(--dxbl-grid-text-cell-padding-y, 0.25rem) 0.3125rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.clickable-cell-button .dxbl-btn {
    --dxbl-btn-padding-y: 0;
}

    .clickable-text:hover {
        cursor: pointer;
        background: rgba(148, 148, 148, 0.3);
        border-radius: 2px;
    }
