/*
    FocusOnNavigate moves focus to the page heading after every navigation, so that a screen
    reader announces which page it landed on instead of leaving the user at the top of the
    document with no signal. Blazor gives the heading tabindex="-1" to make that possible, and
    the browser then paints its focus ring around the title - visibly, on every single page.

    Suppressing the ring here costs keyboard users nothing: tabindex="-1" keeps the heading out
    of the tab order, so it can only ever be focused programmatically. The announcement, which
    is the point of the behaviour, is unaffected.
*/
h1[tabindex="-1"]:focus,
h1[tabindex="-1"]:focus-visible {
    outline: none;
}

/*
   The grid gives every tile a fixed aspect ratio. That is what makes row virtualisation stable:
   every row has the same height, so Virtualize can compute a constant ItemSize
   (Pflichtenheft 8.5, 14.2).
*/
.asset-grid {
    display: grid;

    /*
        Three across, stated rather than derived. auto-fill with a minimum lands on whatever the
        column width happens to divide by, which is how this view ended up with four stamps at one
        width and two large tiles at another. Three is the layout; the breakpoints below give up
        columns rather than let the tiles fall below a usable size.
    */
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 16px;
}

@media (max-width: 1200px) {
    .asset-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@media (max-width: 760px) {
    .asset-grid {
        grid-template-columns: minmax(0, 1fr);
    }
}

.asset-tile {
    position: relative;
    aspect-ratio: 4 / 3;
    border-radius: 6px;
    overflow: hidden;
    background: var(--mud-palette-background-grey);
    cursor: pointer;
}

/* Visible focus indicator, required for keyboard operation (NFA-402, FA-907). */
.asset-tile:focus-visible {
    outline: 3px solid var(--mud-palette-primary);
    outline-offset: 2px;
}

.asset-tile__image {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/* Source and status share one row in the top right corner, so neither has to know about the
   other and the top left stays free for the selection circle. */
.asset-tile__corner {
    position: absolute;
    top: 8px;
    right: 8px;
    display: flex;
    align-items: center;
    gap: 4px;
}

/* The remove button sits on the tile itself, opposite the source badge, and only appears for
   somebody who may edit the collection. */
.collection-item {
    position: relative;
}

.collection-item__remove {
    position: absolute;
    top: 6px;
    left: 6px;
}

.collection-item__remove .mud-icon-button {
    background: rgba(0, 0, 0, 0.55);
    color: #FFFFFF;
}

/* The source badge carries the icon and nothing else (FA-401). Without this it keeps the padding
   and the icon margin a chip reserves for a label that is no longer there, and sits on the picture
   as a wide empty lozenge. */
.source-badge {
    min-width: 0;
    padding-inline: 6px;
}

.source-badge .mud-chip-icon {
    margin: 0;
}

.asset-tile__status {
    display: inline-flex;
    background: rgba(0, 0, 0, 0.55);
    border-radius: 50%;
    padding: 2px;
}

/* The AI badge draws a ring around its icon while the analysis is outstanding. A still hourglass
   said only that the work had not finished; the ring says it is under way, which is the difference
   between "stuck" and "wait a moment" to somebody who has just uploaded fifty files.

   The ring is drawn inside the badge rather than around it, so this badge measures the same as the
   availability one beside it and the corner row keeps its rhythm. That is what the icon shrinks
   for - the 20 px it would take leaves the ring nowhere to sit. */
.asset-tile__ai {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
}

.asset-tile__ai::before {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: 50%;
    border: 2px solid rgba(255, 255, 255, 0.25);
    border-top-color: var(--mud-palette-info);
    animation: asset-tile-ai-spin 1.4s linear infinite;
}

.asset-tile__ai .mud-icon-root {
    font-size: 12px;
    width: 12px;
    height: 12px;
}

@keyframes asset-tile-ai-spin {
    to {
        transform: rotate(1turn);
    }
}

/* The motion is decoration: the icon, the tooltip and the screen-reader text each say what is
   happening on their own, so switching it off costs nothing (NFA-402). The ring stays - it is what
   makes the badge legible as "AI" rather than a second availability mark. */
@media (prefers-reduced-motion: reduce) {
    .asset-tile__ai::before {
        animation: none;
    }
}

.asset-tile__tags {
    position: absolute;
    bottom: 34px;
    left: 6px;
    right: 6px;
    display: flex;
    flex-wrap: wrap;
    gap: 2px;
}

.asset-tile__caption {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    padding: 4px 8px;
    background: rgba(0, 0, 0, 0.6);
    color: #fff;
    font-size: 0.75rem;
    display: flex;
    justify-content: space-between;
    gap: 8px;
}

.asset-tile__name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Layout is fully usable from 1280 px and workable from 768 px (FA-909). */
@media (max-width: 768px) {
    .asset-grid {
        grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
    }
}

/* --- Asset detail --------------------------------------------------------- */

.asset-preview {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 320px;
    max-height: 70vh;
    overflow: hidden;
    cursor: zoom-in;
    background: repeating-conic-gradient(#e9e9ec 0% 25%, #f6f6f8 0% 50%) 50% / 24px 24px;
}

.asset-preview__image {
    max-width: 100%;
    max-height: 70vh;
    object-fit: contain;
    display: block;
}

.asset-preview__zoom {
    position: absolute;
    right: 12px;
    bottom: 12px;
    padding: 6px;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.55);
    color: #fff;
    display: flex;
}

.origin-table th,
.metadata-table th {
    width: 34%;
    text-align: left;
    font-weight: 500;
    vertical-align: top;
    white-space: nowrap;
}

.metadata-table td {
    word-break: break-word;
}

.origin-mono {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.85em;
}

/* The origin marker is a label, not a colour: it has to survive greyscale (NFA-403, FA-311). */
.metadata-origin {
    margin-left: 8px;
    padding: 1px 6px;
    border: 1px solid currentColor;
    border-radius: 10px;
    font-size: 0.7rem;
    opacity: 0.75;
    white-space: nowrap;
}

.dominant-color {
    width: 32px;
    height: 32px;
    border-radius: 4px;
    border: 1px solid rgba(0, 0, 0, 0.2);
    display: inline-block;
}

.keyword-chip--weak {
    opacity: 0.65;
}

.duplicate-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 8px 0;
    border-top: 1px solid var(--mud-palette-lines-default);
}

.duplicate-row:first-of-type {
    border-top: 0;
}

.duplicate-row__thumb {
    width: 72px;
    height: 54px;
    object-fit: cover;
    border-radius: 4px;
    flex: 0 0 auto;
}

.duplicate-row__body {
    flex: 1 1 auto;
    min-width: 0;
}

.duplicate-row__source {
    font-weight: 600;
    margin-right: 6px;
}

/* --- Lightbox (FA-905) ---------------------------------------------------- */

.lightbox {
    position: fixed;
    inset: 0;
    z-index: 2000;
    background: rgba(0, 0, 0, 0.92);
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    touch-action: none;
}

.lightbox:focus-visible {
    outline: 3px solid #fff;
    outline-offset: -3px;
}

.lightbox__image {
    max-width: 96vw;
    max-height: 88vh;
    object-fit: contain;
    transform-origin: center center;
    user-select: none;
    will-change: transform;
}

.lightbox__bar {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    display: flex;
    align-items: center;
    gap: 4px;
    padding: 8px 12px;
    color: #fff;
    background: linear-gradient(rgba(0, 0, 0, 0.6), transparent);
}

.lightbox__title {
    font-size: 0.95rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.lightbox__spacer {
    flex: 1 1 auto;
}

.lightbox__nav {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    width: 56px;
    height: 56px;
    border: 0;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.14);
    color: #fff;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
}

.lightbox__nav:hover { background: rgba(255, 255, 255, 0.28); }

.lightbox__nav:focus-visible {
    outline: 3px solid #fff;
    outline-offset: 2px;
}

.lightbox__nav--previous { left: 16px; }
.lightbox__nav--next { right: 16px; }

.lightbox__hint {
    position: absolute;
    bottom: 12px;
    left: 0;
    right: 0;
    text-align: center;
    color: rgba(255, 255, 255, 0.75);
    font-size: 0.8rem;
}

.lightbox__hint kbd {
    padding: 1px 5px;
    border: 1px solid rgba(255, 255, 255, 0.4);
    border-radius: 3px;
    font-size: 0.75rem;
}

/* Screen-reader-only text, used where a colour swatch needs a name (NFA-403). */
.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}

/* --- Skins ----------------------------------------------------------------
   The interface is themed by MudBlazor, which sets --mud-palette-* at runtime, and almost
   everything below reads those. Sign-in and access denied cannot: they render statically, with no
   theme provider above them, so they would keep the product's colours while the rest of the
   application wore the customer's. These variables give those pages the same switch. The body
   carries data-theme, set from Display:Skin.
   -------------------------------------------------------------------------- */

:root {
    --cmo-page: #f4f5f7;
    --cmo-surface: #fff;
    --cmo-text: inherit;
    --cmo-border: #c4c7cc;
    --cmo-accent: #1a73e8;
    --cmo-accent-hover: #1765cc;
    --cmo-accent-text: #fff;
    --cmo-focus: #0b3d91;
    --cmo-danger: #d32f2f;
    --cmo-danger-bg: #fdecea;
    --cmo-danger-text: #611a15;
    --cmo-radius: 10px;
    --cmo-radius-small: 6px;
    --cmo-font: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    --cmo-card-shadow: 0 2px 16px rgba(0, 0, 0, 0.12);
}

/*
    Read off the customer's own site rather than guessed: navy #000066 for anything that leads,
    #0000EE for links, the greys its panels are built from, and square corners throughout. The type
    is Verdana as there, but not the 11px of the original - matching a house style is worth doing,
    matching its accessibility problems is not (NFA-403).
*/
body[data-theme="steeltags"] {
    --cmo-page: #bebebe;
    --cmo-surface: #fff;
    --cmo-border: #999;
    --cmo-accent: #000066;
    --cmo-accent-hover: #000099;
    --cmo-focus: #0000ee;
    --cmo-danger: #c00;
    --cmo-danger-bg: #f7e4e4;
    --cmo-danger-text: #600;
    --cmo-radius: 0;
    --cmo-radius-small: 0;
    --cmo-font: Verdana, Geneva, sans-serif;
    --cmo-card-shadow: 0 1px 4px rgba(0, 0, 0, 0.35);
    --cmo-heading: #000066;
}

@media (prefers-color-scheme: dark) {
    :root {
        --cmo-page: #1b1b1f;
        --cmo-surface: #26262b;
        --cmo-text: #e8e8ea;
        --cmo-border: #4a4a52;
        --cmo-danger-bg: #3b1f1d;
        --cmo-danger-text: #ffb4ab;
    }

    body[data-theme="steeltags"] {
        --cmo-page: #101018;
        --cmo-surface: #1c1c24;
        --cmo-text: #e8e8ea;
        --cmo-border: #3a3a48;
        --cmo-accent: #2b2b8f;
        --cmo-accent-hover: #3a3ab0;
        --cmo-focus: #8f9ce0;
        --cmo-heading: #cfd4f5;
    }
}

/*
    The one thing a palette cannot express: on the original every panel is a box with a hairline
    border and no shadow, which is what gives that site its squared-off, technical feel. Scoped to
    the content area so the app bar, menus and dialogs keep their own treatment.
*/
body[data-theme="steeltags"] .mud-main-content .mud-paper,
body[data-theme="steeltags"] .mud-main-content .mud-card {
    border: 1px solid var(--cmo-border);
    box-shadow: none;
}

/*
    On that site the grey is only ever the gap between boxes - fields are white, panels are white,
    nothing floats on the background. Our own palette needs none of this: against a near-white page
    an outlined field reads perfectly well unfilled. On grey it becomes a line drawing, and a search
    box the whole catalogue is built around disappears into the page. These are surfaces the skin
    puts back, not layout it moves.
*/

/* Fields. Outlined inputs are transparent by default - this covers every page at once. */
body[data-theme="steeltags"] .mud-input.mud-input-outlined,
body[data-theme="steeltags"] .mud-input.mud-input-filled {
    background-color: var(--cmo-surface);
}

/*
    The search, which is the one control the catalogue is arranged around. Only the colours: the
    geometry, and the sticky behaviour that depends on it, belong to the layout and are the same in
    every skin.
*/
body[data-theme="steeltags"] .catalog-search {
    background: var(--cmo-surface);
}

/* A dashed outline on grey reads as a gap in the page rather than as a target for a file. */
body[data-theme="steeltags"] .upload-drop {
    background: var(--cmo-surface);
}

/*
    Page titles carry the skin's colour but no box. A bar was tried - it is what the template puts
    above every panel - and it read as heavy above a page that is already a stack of boxes.
*/
body[data-theme="steeltags"] .mud-main-content h1.mud-typography {
    color: var(--cmo-heading);
}

/*
    Every alert in the application is the text variant, which draws itself from a 6%-opaque tint of
    its severity colour. Against white that is a readable wash; against this skin's grey it is
    nothing at all, and a paragraph of explanation sits on the page like stray text. The surface
    goes underneath it; severity keeps saying what it says, through the icon and the text colour.
*/
body[data-theme="steeltags"] .mud-alert {
    border: 1px solid var(--cmo-border);
    background-color: var(--cmo-surface);
}

/* The result count, the sort and the density switch, which otherwise sit on the page itself. */
body[data-theme="steeltags"] .catalog-toolbar {
    background: var(--cmo-surface);
    border: 1px solid var(--cmo-border);
    padding: 8px 12px;
}

/* --- Sign-in and access denied -------------------------------------------- */
/* Statically rendered pages, so they carry their own styling rather than relying on MudBlazor. */

.login-page {
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--cmo-page);
    font-family: var(--cmo-font);
}

.login-card {
    width: min(420px, calc(100vw - 32px));
    padding: 32px;
    background: var(--cmo-surface);
    color: var(--cmo-text);
    border-radius: var(--cmo-radius);
    box-shadow: var(--cmo-card-shadow);
}

.login-title {
    margin: 0 0 24px;
    font-size: 1.4rem;
    font-weight: 600;
}

.login-label {
    display: block;
    margin: 16px 0 4px;
    font-size: 0.875rem;
    font-weight: 500;
}

.login-input {
    width: 100%;
    padding: 10px 12px;
    border: 1px solid var(--cmo-border);
    border-radius: var(--cmo-radius-small);
    font-size: 1rem;
    box-sizing: border-box;
    background: var(--cmo-surface);
    color: var(--cmo-text);
    font-family: inherit;
}

.login-input:focus-visible {
    outline: 2px solid var(--cmo-accent);
    outline-offset: 1px;
    border-color: var(--cmo-accent);
}

.login-check {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 16px 0;
    font-size: 0.875rem;
}

.login-button {
    width: 100%;
    padding: 11px;
    margin-top: 8px;
    border: 0;
    border-radius: var(--cmo-radius-small);
    background: var(--cmo-accent);
    color: var(--cmo-accent-text);
    font-size: 1rem;
    font-weight: 500;
    font-family: inherit;
    cursor: pointer;
}

.login-button:hover { background: var(--cmo-accent-hover); }

.login-button:focus-visible {
    outline: 3px solid var(--cmo-focus);
    outline-offset: 2px;
}

/* Never colour alone: the message carries the meaning (NFA-403). */
.login-error {
    padding: 12px;
    margin-bottom: 16px;
    border-left: 4px solid var(--cmo-danger);
    background: var(--cmo-danger-bg);
    color: var(--cmo-danger-text);
    font-size: 0.9rem;
}

.validation-message {
    display: block;
    margin-top: 4px;
    color: var(--cmo-danger);
    font-size: 0.8rem;
}

/* --- Upload (FA-1302) ----------------------------------------------------- */

.upload-drop {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 40px 24px;
    border: 2px dashed var(--mud-palette-lines-default);
    border-radius: 8px;
    text-align: center;
}

.upload-drop--active {
    border-color: var(--mud-palette-primary);
    background: var(--mud-palette-action-default-hover);
}

/* The inputs are driven from JavaScript; the buttons above them are what the user sees. */
.upload-input {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    pointer-events: none;
}

.upload-row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 12px;
    border-top: 1px solid var(--mud-palette-lines-default);
}

.upload-row:first-of-type { border-top: 0; }

.upload-row__body {
    flex: 1 1 auto;
    min-width: 0;
}

.upload-row__name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* --- Dashboard ------------------------------------------------------------ */

.dashboard-tile__value {
    font-size: 1.75rem;
    font-weight: 600;
    line-height: 1.2;
}

.dashboard-tile__caption {
    font-size: 0.8rem;
    opacity: 0.7;
}

.distribution-row { margin-bottom: 12px; }

.distribution-bar {
    height: 8px;
    border-radius: 4px;
    background: var(--mud-palette-action-default-hover);
    overflow: hidden;
}

.distribution-bar__fill {
    height: 100%;
    border-radius: 4px;
}

/* --- Sources -------------------------------------------------------------- */

.source-card { height: 100%; }

.source-card__failed { color: var(--mud-palette-error); }

.source-color-preview {
    width: 40px;
    height: 40px;
    border-radius: 6px;
    border: 1px solid var(--mud-palette-lines-default);
    align-self: center;
}

.ingest-current {
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    opacity: 0.7;
}

/* --- Duplicates ----------------------------------------------------------- */

.duplicate-group {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 12px;
}

.duplicate-card {
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: 6px;
    overflow: hidden;
}

.duplicate-card__image {
    width: 100%;
    aspect-ratio: 4 / 3;
    object-fit: cover;
    display: block;
}

.duplicate-card__body { padding: 8px; }

.duplicate-card__name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.duplicates-slider { max-width: 320px; }

/* --- Keyword review and rights -------------------------------------------- */

.review-row {
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 10px 16px;
    border-top: 1px solid var(--mud-palette-lines-default);
    flex-wrap: wrap;
}

.review-row:first-of-type { border-top: 0; }

.review-row__body { flex: 1 1 240px; }

.review-row__actions {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

.review-row__merge { min-width: 220px; }

.rights-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 0 12px;
}

.contrast-bad { color: var(--mud-palette-error); font-weight: 600; }
.contrast-good { color: var(--mud-palette-success); }

/* --- Colour quick pick (FA-702) ------------------------------------------- */

.color-palette {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

.color-palette__swatch {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    padding: 0;
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: var(--mud-default-borderradius);
    font-size: 0.9rem;
    line-height: 1;
    cursor: pointer;
}

.color-palette__swatch--selected {
    border-color: var(--mud-palette-text-primary);
    border-width: 2px;
}

/*
    The swatches carry no text, so the focus ring is the whole of what a keyboard user has to go on.
    Drawn outside the box because inside it vanishes against the darker half of the palette.
*/
.color-palette__swatch:focus-visible {
    outline: 2px solid var(--mud-palette-primary);
    outline-offset: 2px;
}

.audit-details {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.75rem;
    opacity: 0.8;
}

/* --- Catalogue density (FA-902) ------------------------------------------- */

/*
    The list density is a row, not a tile with a picture in it. Everything on the tile is absolutely
    positioned over a 4:3 image, which is right for the grid and wrong here: the thumbnail shrinks
    to a corner while the dark caption bar and the badges stay stretched across the full width of
    the row, over empty background. Each part is put back into the flow and laid out left to right.
*/
.asset-grid--list {
    grid-template-columns: minmax(0, 1fr);
    gap: 6px;
}

.asset-grid--list .asset-tile {
    aspect-ratio: auto;
    height: auto;
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 6px 12px 6px 6px;
    background: var(--mud-palette-surface);
    border: 1px solid var(--mud-palette-lines-default);
}

.asset-grid--list .asset-tile:hover {
    background: var(--mud-palette-action-default-hover);
}

.asset-grid--list .asset-tile__image {
    width: 128px;
    height: 84px;
    border-radius: 4px;
    flex: none;
    order: 1;
}

/* Out of the overlay and onto the surface: dark-on-image is unreadable off the image. */
.asset-grid--list .asset-tile__caption {
    position: static;
    order: 2;
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
    padding: 0;
    background: none;
    color: inherit;
    font-size: 0.875rem;
}

.asset-grid--list .asset-tile__name {
    font-weight: 500;
    max-width: 100%;
}

.asset-grid--list .asset-tile__meta {
    color: var(--mud-palette-text-secondary);
    font-size: 0.75rem;
}

.asset-grid--list .asset-tile__tags {
    position: static;
    order: 3;
    flex: 0 1 auto;
    width: auto;
    justify-content: flex-end;
}

.asset-grid--list .asset-tile__status {
    position: static;
    order: 4;
    flex: none;
    padding: 0;
    background: none;
    border-radius: 0;
    display: flex;
}

.asset-grid--list .asset-tile__corner {
    position: static;
    order: 5;
    flex: none;
}

.asset-grid--list .asset-tile__select {
    position: static;
    order: 0;
    flex: none;
    background: none;
}

/* The frame sits inside the tile, so a selected image keeps its place in the grid instead of
   nudging its neighbours. */
.asset-tile--selected {
    outline: 3px solid var(--mud-palette-primary);
    outline-offset: -3px;
}

/* Out of the way until wanted: on hover, while selected, and whenever anything inside the tile has
   keyboard focus - without that last one the circle would be unreachable by keyboard. */
.asset-tile__select {
    position: absolute;
    top: 8px;
    left: 8px;
    background: rgba(255, 255, 255, 0.85);
    border-radius: 50%;
    opacity: 0;
    transition: opacity 120ms ease-in-out;
}

.asset-tile:hover .asset-tile__select,
.asset-tile:focus-within .asset-tile__select,
.asset-tile--selected .asset-tile__select {
    opacity: 1;
}

/* A pointer that never rests, on a touch screen, would leave the circle invisible for good. */
@media (hover: none) {
    .asset-tile__select {
        opacity: 1;
    }
}

/* --- Saved searches (FA-808) ---------------------------------------------- */

.saved-search {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 2px 0;
}

/* --- Similar images (FA-811) ---------------------------------------------- */

.similar-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
    gap: 8px;
}

.similar-card {
    display: block;
    border: 1px solid var(--mud-palette-lines-default);
    border-radius: 6px;
    overflow: hidden;
    text-decoration: none;
    color: inherit;
}

.similar-card__image {
    width: 100%;
    aspect-ratio: 4 / 3;
    object-fit: cover;
    display: block;
}

.similar-card__caption {
    display: block;
    padding: 4px 6px;
    font-size: 0.75rem;
}

.similar-card__name {
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.similar-card__meta {
    display: block;
    opacity: 0.7;
}

/* --- Age distribution (FA-407) -------------------------------------------- */

.age-row { margin-bottom: 12px; }

.age-bar {
    display: flex;
    height: 14px;
    border-radius: 7px;
    overflow: hidden;
    background: var(--mud-palette-action-default-hover);
}

.age-bar__part { height: 100%; }

.age-legend {
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
    font-size: 0.8rem;
    opacity: 0.85;
}

.age-swatch {
    display: inline-block;
    width: 12px;
    height: 12px;
    border-radius: 3px;
    margin-right: 4px;
    vertical-align: -1px;
}

/* Four steps of one hue: the order is the message, not the colour itself (NFA-403). */
.age-swatch--month { background: #1A73E8; }
.age-swatch--year { background: #5B9BF0; }
.age-swatch--three { background: #9DC2F7; }
.age-swatch--older { background: #D6E4FB; }

/* --- Passkey sign-in (FA-1203) -------------------------------------------- */

.login-passkey { margin-top: 4px; }

.login-separator {
    display: flex;
    align-items: center;
    gap: 12px;
    margin: 20px 0 16px;
    font-size: 0.85rem;
    opacity: 0.7;
}

.login-separator::before,
.login-separator::after {
    content: '';
    flex: 1;
    height: 1px;
    background: currentColor;
    opacity: 0.3;
}

.login-button--secondary {
    background: transparent;
    color: inherit;
    border: 1px solid currentColor;
}

.passkey-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 0;
    border-bottom: 1px solid var(--mud-palette-divider);
}

.passkey-row:last-child { border-bottom: none; }

/* --- Circuit failure banner (NFA-405) ------------------------------------- */

/* Blazor toggles display on this element itself, so the layout lives on the children. */
#blazor-error-ui {
    position: fixed;
    inset: auto 0 0 0;
    z-index: 2000;
    display: none;
    align-items: center;
    gap: 16px;
    padding: 12px 20px;
    background: #B3261E;
    color: #FFFFFF;
    box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.3);
}

.blazor-error-ui__text { flex: 1; }

#blazor-error-ui a {
    color: #FFFFFF;
    text-decoration: underline;
    white-space: nowrap;
}

/* --- Provider model editor (FA-1204) -------------------------------------- */

.provider-row {
    padding: 12px 0;
    border-bottom: 1px solid var(--mud-palette-divider);
}

.provider-row:last-child { border-bottom: none; }

.provider-row__head {
    display: flex;
    align-items: center;
    margin-bottom: 8px;
}

/* Two columns where a region applies, one where it does not. */
.provider-row__fields {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: 12px;
}

/* --- Account (FA-1202, FA-1203) ------------------------------------------- */

/*
    A form column rather than the full card width. Names and paths want the room; a password does
    not, and a field a metre wide makes the caret hard to find.
*/
.account-form {
    max-width: 420px;
}

/* --- Catalogue search (FA-801, FA-813) ------------------------------------ */

/*
    Above everything else, on its own panel. It is the control every visit to this page starts
    with; sitting in the filter column it carried the same weight as a checkbox.
*/
.catalog-search {
    /*
        A panel, not a bar: as wide as the two columns beneath it and no wider. Out to the edge of
        the window it read as a second application bar; centred at a fixed width it floated free of
        the grid it belongs to. Aligned with the content, it is part of the page.

        The width comes from the container rather than from a number here - no max-width, no auto
        margins - so it lines up with the filter column on the left and the tiles on the right at
        every window size, and keeps the same distance from the edge as everything else.
    */
    margin: 0 0 20px;
    padding: 12px 16px 10px;
    border-radius: var(--mud-default-borderradius);

    /*
        The surface colour, not the page colour: white in the light theme, and correspondingly dark
        in the dark one. A literal white would be a bright slab across a dark page at night.

        The shadow falls downward only - a negative spread pulls it back off the sides, so the panel
        casts onto what scrolls underneath it rather than outlining itself on all four edges.
    */
    background: var(--mud-palette-surface);
    box-shadow: 0 6px 10px -6px rgba(0, 0, 0, 0.35);
}

/*
    Pinned, when the user asks for it. Being at the top of the page is not the same as being
    reachable: two screens into a result set the search was gone, and the way back to it was to
    scroll up past everything one had just scrolled through.

    Off by default, because it costs a strip of every screen on a page made of pictures. The pin
    beside the hint turns it on and the choice is remembered per user.

    top is the application bar's own height - MudMainContent is padded down by that much, so top: 0
    would park this behind the bar rather than beneath it. And that height is not one number:
    MudBlazor shortens the bar on small screens and shortens it again in landscape, with exactly the
    two breakpoints mirrored below. Getting it wrong is quiet either way - too small hides the field
    behind the bar, too large leaves a slit through which the page scrolls.
*/
.catalog-search--sticky {
    position: sticky;
    top: calc(var(--mud-appbar-height, 64px) - var(--mud-appbar-height, 64px) / 8);

    /* Above the tiles that scroll underneath, far below MudBlazor's overlays and popovers. */
    z-index: 3;
}

@media (min-width: 0px) and (orientation: landscape) {
    .catalog-search--sticky {
        top: calc(var(--mud-appbar-height, 64px) - var(--mud-appbar-height, 64px) / 4);
    }
}

@media (min-width: 600px) {
    .catalog-search--sticky {
        top: var(--mud-appbar-height, 64px);
    }
}

/*
    Above the field, not below it. Underneath, the hint sat between the search and the results and
    read as a caption on the wrong thing; the pin was two hundred pixels from the panel edge it
    controls. Above, both belong to the search they describe.
*/
.catalog-search__header {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 6px;
}

/* Taller and larger than a form field, because this one is the point of the page. */
.catalog-search .mud-input.mud-input-outlined {
    font-size: 1.15rem;
}

.catalog-search .mud-input.mud-input-outlined > input {
    padding-top: 16px;
    padding-bottom: 16px;
}

.catalog-search .mud-input-outlined .mud-input-outlined-border {
    border-width: 2px;
}

.catalog-search__hint {
    display: block;
    flex: 1 1 auto;
    text-align: center;
    line-height: 1.4;
}

/* A tag's colour beside its name in the filter picker, so the list reads like the chips do. */
.tag-swatch {
    display: inline-block;
    width: 12px;
    height: 12px;
    border-radius: 3px;
    flex: none;
}

/*
    The build number at the foot of the navigation column. Pinned to the bottom rather than left to
    trail the last menu entry, because on a short menu that lands it in the middle of nothing.

    Absolute against the drawer, which MudBlazor positions itself, so this does not turn the drawer
    content into a flex container and does not depend on any of its internal classes. NavMenu decides
    whether the element exists at all - it is absent from the collapsed icon rail.
*/
.mud-drawer .app-version {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    padding: 8px 16px;
    font-size: 0.75rem;
    line-height: 1.2;
    text-align: center;
    color: var(--mud-palette-text-disabled);
    border-top: 1px solid var(--mud-palette-divider);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
