html, body {
    height: 100%;
    margin: 0;
    font-family: var(--font-sans);
    font-size: 14px;
    background-color: var(--background);
    color: var(--foreground);
    color-scheme: light;
}

.dark body,
html.dark {
    color-scheme: dark;
}

/* The app shell owns all scrolling (sidebar and content are the only scroll
   containers). Without this, any stray flow content makes the document itself
   scrollable, and wheel input over the nav moves the whole page. Guarded by
   :has so standalone documents (login page) keep normal document scrolling. */
body:has(.shell) {
    overflow: hidden;
}

*, *::before, *::after {
    box-sizing: border-box;
}

a {
    color: inherit;
}

h1:focus {
    outline: none;
}

::selection {
    background-color: var(--primary);
    color: var(--primary-foreground);
}

/* Slim scrollbars matching the dark design */
* {
    scrollbar-width: thin;
    scrollbar-color: var(--border) transparent;
}

.valid.modified:not([type=checkbox]) {
    outline: 1px solid var(--alert-success);
}

.invalid {
    outline: 1px solid var(--destructive);
}

.validation-message {
    color: var(--destructive);
}

.blazor-error-boundary {
    background-color: var(--alert-danger-bg);
    border: 1px solid var(--alert-danger);
    border-radius: var(--radius);
    padding: 1rem;
    color: var(--alert-danger-foreground);
}

    .blazor-error-boundary::after {
        content: "Ein Fehler ist aufgetreten.";
    }

/* Shared layout for the administration pages (clients, projects, shootings). */
.admin-page h1 {
    margin: 0;
    font-size: 1.35rem;
    font-weight: 700;
    letter-spacing: -0.01em;
}

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

.form-field {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    margin-bottom: 1rem;
}

.form-field-inline {
    flex-direction: row;
    align-items: center;
    gap: 0.5rem;
}

.form-error {
    margin: 0;
    font-size: 0.8rem;
    color: var(--destructive);
}

.form-hint {
    margin: 0;
    font-size: 0.8rem;
    color: var(--muted-foreground);
}

/* Something did not go to plan but nothing is broken and nobody has to act —
   the automatic rollback of a server update is the case this exists for. */
.form-warning {
    margin: 0;
    font-size: 0.8rem;
    color: var(--alert-warning-foreground);
}

.row-actions {
    display: flex;
    align-items: center;
    gap: 0.25rem;
}

.row-actions .icon-button {
    display: grid;
    place-items: center;
    width: 1.9rem;
    height: 1.9rem;
    border: none;
    border-radius: 0.5rem;
    background: transparent;
    color: var(--muted-foreground);
    cursor: pointer;
}

.row-actions .icon-button:hover {
    background: var(--muted);
    color: var(--foreground);
}

.grid-empty {
    padding: 2rem 1rem;
    text-align: center;
    font-size: 0.85rem;
    color: var(--muted-foreground);
}

/* Filter bar above a data grid (shootings, assets). Wraps on narrow widths. */
.filters {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
}

.filters > * {
    min-width: 10rem;
}

/* Capture-metadata range and facet filters below the main filter bar (asset catalog). */
.filters-metadata {
    display: flex;
    flex-wrap: wrap;
    gap: 1.5rem;
}

.filter-range {
    display: flex;
    align-items: center;
    gap: 0.4rem;
}

.filter-range-label {
    font-size: 0.85rem;
    color: var(--muted-foreground);
}

.filter-range-input {
    width: 4.5rem;
    padding: 0.25rem 0.5rem;
    border: 1px solid var(--border);
    border-radius: 0.4rem;
    background: var(--background);
    color: inherit;
}

.filters-facets {
    display: flex;
    flex-wrap: wrap;
    gap: 2rem;
}

.filter-facet {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    max-height: 8rem;
    overflow-y: auto;
}

.facet-label {
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--muted-foreground);
}

.facet-option {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    font-size: 0.85rem;
}

.grid-link {
    color: var(--foreground);
    font-weight: 500;
    text-decoration: none;
}

.grid-link:hover {
    text-decoration: underline;
}

/* Shooting detail page. */
.detail-page {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
}

.detail-back {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    font-size: 0.85rem;
    color: var(--muted-foreground);
    text-decoration: none;
}

.detail-back:hover {
    color: var(--foreground);
}

.detail-grid {
    display: grid;
    grid-template-columns: minmax(8rem, max-content) 1fr;
    gap: 0.6rem 1.5rem;
    font-size: 0.9rem;
}

.detail-grid dt {
    color: var(--muted-foreground);
}

.detail-grid dd {
    margin: 0;
    color: var(--foreground);
}

/* Compact link lists on detail pages (a client's projects/shootings, …). */
.detail-list {
    margin: 0;
    padding: 0;
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    font-size: 0.9rem;
}

.detail-list li {
    display: flex;
    align-items: center;
    gap: 0.75rem;
}

/* Card header with a trailing badge (e.g. asset count). */
.detail-card-header {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
}

.lifecycle-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
}

/* Block-level loading placeholder for slow initial data loads. */
.loading-indicator {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 2.5rem 0;
    color: var(--muted-foreground);
    font-size: 0.9rem;
}

.loading-spinner {
    width: 1.1rem;
    height: 1.1rem;
    border: 2px solid var(--border);
    border-top-color: var(--primary);
    border-radius: 50%;
    animation: loading-spin 0.7s linear infinite;
}

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

/* Asset catalog thumbnail grid. */
.asset-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
    gap: 1rem;
    margin-top: 1.25rem;
}

.asset-tile {
    display: flex;
    flex-direction: column;
    border: 1px solid var(--border);
    border-radius: 0.6rem;
    overflow: hidden;
    background: var(--card);
}

.asset-tile:hover {
    border-color: var(--muted-foreground);
}

/* The thumbnail itself is the button that opens the fullscreen viewer — the
   tile as a whole isn't, so the Keeper/Reject buttons in .asset-meta below
   aren't nested inside it (invalid HTML, breaks click handling). */
.asset-thumb-button {
    display: block;
    width: 100%;
    padding: 0;
    border: none;
    background: none;
    font: inherit;
    color: inherit;
    cursor: pointer;
}

.asset-thumb-button:focus-visible {
    outline: 2px solid var(--primary);
    outline-offset: -2px;
}

.asset-thumb {
    display: grid;
    place-items: center;
    aspect-ratio: 4 / 3;
    background: var(--muted);
    color: var(--muted-foreground);
    overflow: hidden;
}

.asset-thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.asset-meta {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    padding: 0.6rem 0.7rem;
}

.asset-name {
    font-size: 0.82rem;
    font-weight: 500;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.asset-sub {
    font-size: 0.75rem;
    color: var(--muted-foreground);
}

.asset-badges {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
}

.asset-selection {
    display: flex;
    gap: 0.35rem;
    margin-top: 0.15rem;
}

.asset-selection-button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.9rem;
    height: 1.9rem;
    border: 1px solid var(--border);
    border-radius: 0.4rem;
    background: none;
    color: var(--muted-foreground);
    cursor: pointer;
}

.asset-selection-button:hover {
    border-color: var(--muted-foreground);
    color: var(--foreground);
}

.asset-selection-button:focus-visible {
    outline: 2px solid var(--primary);
    outline-offset: 2px;
}

.asset-selection-active-keeper {
    border-color: var(--primary);
    background: var(--primary);
    color: var(--primary-foreground);
}

.asset-selection-active-rejected {
    border-color: var(--destructive);
    background: var(--destructive);
    color: var(--destructive-foreground);
}

/* Fullscreen asset viewer (lightbox). */
.lightbox {
    position: fixed;
    inset: 0;
    z-index: 100;
    display: grid;
    grid-template-columns: auto 1fr auto;
    grid-template-rows: auto 1fr;
    background: rgba(0, 0, 0, 0.92);
    color: #e5e5e5;
    outline: none;
}

.lightbox-toolbar {
    grid-column: 1 / -1;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.6rem 1rem;
    background: rgba(0, 0, 0, 0.55);
}

.lightbox-info {
    display: flex;
    align-items: baseline;
    gap: 0.75rem;
    min-width: 0;
}

.lightbox-title {
    font-size: 0.9rem;
    font-weight: 500;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.lightbox-counter,
.lightbox-zoom {
    font-size: 0.8rem;
    color: #a3a3a3;
    font-variant-numeric: tabular-nums;
}

.lightbox-zoom {
    min-width: 3.2rem;
    text-align: center;
}

.lightbox-actions {
    display: flex;
    align-items: center;
    gap: 0.25rem;
}

.lightbox-button,
.lightbox-nav {
    display: grid;
    place-items: center;
    border: none;
    background: transparent;
    color: #d4d4d4;
    cursor: pointer;
    border-radius: 0.5rem;
}

.lightbox-button {
    width: 2.1rem;
    height: 2.1rem;
}

/* A disabled toolbar button has to look disabled, or the reveal action reads as
   broken rather than unavailable — an archived asset lives on a drive that may
   not be plugged in, and the tooltip says so. .lightbox-nav already had this. */
.lightbox-button:disabled {
    opacity: 0.35;
    cursor: default;
}

.lightbox-button:hover:not(:disabled),
.lightbox-nav:hover:not(:disabled) {
    background: rgba(255, 255, 255, 0.12);
    color: #ffffff;
}

.lightbox-button-active {
    background: rgba(255, 255, 255, 0.18);
    color: #ffffff;
}

.lightbox-nav {
    width: 3rem;
    margin: 0.5rem 0.25rem;
    align-self: stretch;
}

.lightbox-nav:disabled {
    opacity: 0.25;
    cursor: default;
}

.lightbox-stage {
    display: grid;
    place-items: center;
    overflow: hidden;
    /* Wheel zoom replaces scrolling; block browser touch panning too. */
    touch-action: none;
}

.lightbox-image {
    grid-area: 1 / 1;
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
    user-select: none;
    will-change: transform;
    cursor: zoom-in;
}

.lightbox-image-loading {
    visibility: hidden;
}

.lightbox-image-dragging {
    cursor: grabbing;
}

/* Focus sentinels: absolute so they stay out of the overlay's grid flow, and
   zero-sized so nothing shows even while focus passes through them. */
.lightbox-sentinel {
    position: absolute;
    width: 0;
    height: 0;
    outline: none;
}

/* Keyboard legend, toggled with "?" — absolute so it overlays the stage
   instead of taking a cell in the overlay's grid. */
.lightbox-shortcuts {
    position: absolute;
    top: 3.4rem;
    right: 1rem;
    z-index: 1;
    max-width: min(22rem, calc(100vw - 2rem));
    padding: 0.85rem 1rem;
    border: 1px solid rgba(255, 255, 255, 0.15);
    border-radius: 0.6rem;
    background: rgba(0, 0, 0, 0.85);
}

.lightbox-shortcuts-title {
    display: block;
    margin-bottom: 0.6rem;
    font-size: 0.8rem;
    font-weight: 600;
    color: #fafafa;
}

.lightbox-shortcuts-list {
    display: grid;
    grid-template-columns: auto 1fr;
    align-items: center;
    gap: 0.35rem 0.75rem;
    margin: 0;
    font-size: 0.8rem;
    color: #d4d4d4;
}

.lightbox-shortcuts-list dd {
    margin: 0;
}

.lightbox-shortcuts-list kbd {
    display: inline-block;
    min-width: 1.6rem;
    padding: 0.1rem 0.35rem;
    border: 1px solid rgba(255, 255, 255, 0.25);
    border-radius: 0.3rem;
    background: rgba(255, 255, 255, 0.08);
    font-family: inherit;
    font-size: 0.75rem;
    text-align: center;
    color: #fafafa;
}

/* Take-split editor */
.split-meta {
    display: flex;
    gap: 1rem;
    color: var(--muted-foreground);
    font-size: 0.875rem;
}

.split-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 22rem;
    gap: 1.5rem;
    align-items: start;
}

@media (max-width: 900px) {
    .split-layout {
        grid-template-columns: minmax(0, 1fr);
    }
}

.split-main {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    min-width: 0;
}

.split-video {
    width: 100%;
    max-height: 60vh;
    background: #000;
    border-radius: var(--radius);
}

.split-video-placeholder {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 1rem;
    aspect-ratio: 16 / 9;
    color: var(--muted-foreground);
    background: var(--muted);
    text-align: center;
    padding: 1rem;
}

.split-timeline {
    position: relative;
    width: 100%;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    overflow: hidden;
    cursor: pointer;
    user-select: none;
    background: var(--muted);
}

.split-filmstrip {
    display: block;
    width: 100%;
    height: 48px;
    object-fit: cover;
}

.split-waveform {
    display: block;
    width: 100%;
    height: 40px;
    object-fit: fill;
    opacity: 0.85;
}

.split-take-band {
    position: absolute;
    top: 0;
    bottom: 0;
    background: color-mix(in srgb, var(--primary) 28%, transparent);
    border-left: 2px solid var(--primary);
    border-right: 2px solid var(--primary);
    pointer-events: none;
}

.split-marker {
    position: absolute;
    top: 0;
    bottom: 0;
    width: 2px;
    pointer-events: none;
}

.split-marker-in {
    background: var(--alert-success);
}

.split-marker-out {
    background: var(--destructive);
}

.split-playhead {
    position: absolute;
    top: 0;
    bottom: 0;
    width: 2px;
    background: var(--foreground);
    pointer-events: none;
}

.split-hint {
    color: var(--muted-foreground);
    font-size: 0.8125rem;
    margin: 0;
}

.split-side {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

.split-field-label {
    display: block;
    color: var(--muted-foreground);
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

.split-time {
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum";
}

.split-playhead-readout {
    margin-bottom: 0.75rem;
}

.split-inout {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0.75rem;
    margin-bottom: 0.75rem;
}

.split-snap {
    display: block;
    color: var(--muted-foreground);
    font-size: 0.75rem;
    font-variant-numeric: tabular-nums;
}

.split-buttons {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

.split-empty {
    color: var(--muted-foreground);
    font-size: 0.875rem;
    margin: 0;
}

.split-take-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.375rem;
}

.split-take-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    padding: 0.375rem 0.5rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
}

.split-take-remove {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0.25rem;
    border: none;
    background: transparent;
    color: var(--muted-foreground);
    cursor: pointer;
    border-radius: var(--radius);
}

.split-take-remove:hover {
    color: var(--destructive);
    background: var(--muted);
}

/* Sign-in. Shared rather than page-local: the web host renders a standalone
   document (LoginPage) and the desktop host renders LoginView inline, and both
   link this stylesheet. Kept in one place so the two hosts cannot drift apart
   — they already say the same words through the same Login_* resources. */
.login-shell {
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1.5rem;
    background: var(--background);
    color: var(--foreground);
    font-family: var(--font-sans);
}

.login-card {
    width: 100%;
    max-width: 24rem;
    background: var(--card);
    color: var(--card-foreground);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 2rem;
}

.login-brand {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    margin-bottom: 1.75rem;
}

.login-brand img { width: 1.75rem; height: 1.75rem; }
.login-brand span { font-size: 1.125rem; font-weight: 600; }

.login-title {
    font-size: 1.25rem;
    margin: 0 0 1.25rem;
}

.login-field { margin-bottom: 1rem; }

.login-field label {
    display: block;
    margin-bottom: 0.375rem;
    font-size: 0.875rem;
    font-weight: 500;
}

.login-field input {
    width: 100%;
    padding: 0.5rem 0.75rem;
    font: inherit;
    color: var(--foreground);
    background: var(--input);
    border: 1px solid var(--border);
    border-radius: calc(var(--radius) - 2px);
}

.login-field input:focus-visible {
    outline: 2px solid var(--ring);
    outline-offset: 1px;
}

.login-submit {
    width: 100%;
    margin-top: 0.5rem;
    padding: 0.5rem 1rem;
    font: inherit;
    font-weight: 500;
    color: var(--primary-foreground);
    background: var(--primary);
    border: none;
    border-radius: calc(var(--radius) - 2px);
    cursor: pointer;
}

/* The desktop disables the button for the duration of the attempt; without
   this it looks exactly like a button that simply ignores the click. */
.login-submit:disabled {
    opacity: 0.6;
    cursor: default;
}

.login-error {
    margin-bottom: 1.25rem;
    padding: 0.625rem 0.75rem;
    font-size: 0.875rem;
    color: var(--alert-danger-foreground);
    background: var(--alert-danger-bg);
    border: 1px solid var(--alert-danger);
    border-radius: calc(var(--radius) - 2px);
}

.login-note {
    margin-top: 1.5rem;
    font-size: 0.8125rem;
    color: var(--muted-foreground);
}

/* Motion sensitivity: the operating-system setting wins. !important also
   reaches the component-scoped stylesheets, which the cascade would otherwise
   let outrank this file. */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }

    /* The spinner is the only sign that a long ingest is still alive — slowed
       rather than stopped, because a frozen spinner reads as a hung app. */
    .loading-spinner {
        animation-duration: 2.4s !important;
        animation-iteration-count: infinite !important;
    }
}
